diff --git a/AUTHORS b/AUTHORS index a2afd50c..9adf2005 100755 --- a/AUTHORS +++ b/AUTHORS @@ -9,6 +9,7 @@ Christian Sterzl DaveLaw Dave Brosius Dawid Rusin +Denis Stepanov Emil Lundberg Enrique da Costa Cambio Jacob Middag @@ -34,6 +35,8 @@ Robbert Jan Grootjans Robert Wertman Roel Spilker Roland Praml +Rostislav Krasny <45571812+rosti-il@users.noreply.github.com> +Samuel Pereira Sander Koning Szymon Pacanowski Taiki Sugawara diff --git a/build.xml b/build.xml index 494d3d0f..5a1a67a0 100644 --- a/build.xml +++ b/build.xml @@ -19,1156 +19,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> - + This buildfile is part of projectlombok.org. It is the main entry point that contains the common tasks and can be called on to run the main aspects of all the sub-scripts. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A new version of ivyplusplus was required and has been downloaded. Rerun the script to continue. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Lombok version: ${lombok.version} (${lombok.fullversion}) - - - - - - - - - - - - - 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. - - - - -For compiling with Java9 'modulepath' an Ant version 1.9.7+ or 1.10.0+ is required. -Your current version is: - ${ant.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lombok.launch.AnnotationProcessorHider$AnnotationProcessor -lombok.launch.AnnotationProcessorHider$ClaimingProcessor - - lombok.launch.AnnotationProcessorHider$AnnotationProcessor,isolating -lombok.launch.AnnotationProcessorHider$ClaimingProcessor,isolating - - - - - - - - - - - - - - - - ${releaseTimestamp} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** WARNING ** The core lombok contributors all use eclipse to develop lombok. We have some ability on letting you work on lombok via intellij, but whether the generated project can be used in a modern intellij is currently unknown. Please do continue, but be aware that trying to work on lombok from intellij may run into problems. If you want to adopt 'work on lombok via intellij' as a task, we're open to it! - Press return to continue - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - To add your eclipse installation's own plugins as dependencies, the build script needs to know where your eclipse is installed. Please enter this now (it's saved for future executions of this task). For example: - - /Applications/eclipse - C:\Program Files\eclipse - - - - Eclipse can't be found in this location; I expect that directory to contain a subdirectory called 'plugins'. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - You do not have the eclipse plugin '${pluginName}'. I expected it to be in your eclipse plugins directory (followed by an underscore and a version number). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Added to project classpath from your eclipse installation: ${pluginName}. -${sourceWarning} - - - - - - - - - - - - - - - - - - - - - - - - - - Testing ECJ using ECJ: ${ecj.loc} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WARNING: If you wish to test JDK8 features in eclipse, there must be a JDK8 installation configured in your eclipse, and it must be called 'JavaSE-1.8'. - - - - - - - - - - - - - - Tests will now run against OpenJDK6 - - - - - - - - - - - - - - - Tests will now run against OpenJDK7 - - - - - - - - - - - - - - - Tests will now run against Oracle JDK7 - - - - - - - - - - - - - - - - Tests will now run against Oracle JDK8 - - - - - ERROR: No test environment set up. - -You need to set up a test environment, which consists of a version of javac, and a JRE runtime classpath ('rt.jar'). -Eventually, this environment concept will be extended to also include an ecj and/or eclipse to test against. - -You can let this ant script set them up for you: - -* ant setupJavaOpenJDK6TestEnvironment -* ant setupJavaOpenJDK7TestEnvironment -* ant setupJavaOracle7TestEnvironment -* ant setupJavaOracle8TestEnvironment - -These will set up test environments based on OpenJDK6 and OpenJDK7, and download all required files automatically. This will be a relatively large download. You can switch by running this command again; the downloads are cached so switching is fast. - -You can also create your own by writing a 'testenvironment.properties' file. The relevant properties are: - -* test.location.javac = /path/to/javac6.jar -* test.location.ecj = /path/to/ecj6.jar -* test.location.bootclasspath = /path/to/rt.jar -* test.location.name = RandomUsefulNameToIdentifyThisSetup -* test.javaversion = 6 - - - - - - - - - - - - - - - - - - - - - - - - Running test suite in JDK9+ mode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Running test suite in JDK6-8 mode - - - - - - - - - - - - - - - - - - - - - - - - - - -
Lombok - ]]>v${lombok.version}
- Copyright © 2011-${javadoc.year} The Project Lombok Authors, licensed under the MIT licence.]]> -
- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The artifact has been published to staging. Now go to https://oss.sonatype.org/ and log in as Reinier, then doublecheck if all is well and 'release' it. - - - - - - - - - WARNING: You should now immediately run an edge release! - - - - - - - - - - - - - - - - - - - Aborted. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.projectlombok.testAp.TestAp - - - - - - - - - - - - - - - - Running in order: First Lombok, Then testAP - - - - - - - - - - - - Running in order: First TestAP, Then Lombok - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lombok.mapstruct.NotifierHider$AstModificationNotifier - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + +
diff --git a/buildScripts/build-support.ant.xml b/buildScripts/build-support.ant.xml new file mode 100644 index 00000000..107f5f47 --- /dev/null +++ b/buildScripts/build-support.ant.xml @@ -0,0 +1,113 @@ + + + +This buildfile is part of projectlombok.org. It is responsible for tasks that help with setting up the build infrastructure. +None of these tasks are normally needed, unless modifying how the build works, such as updating dependencies. + + + + + + + + + + + + You need to specify the JDK9+ jdk whose jdk.compiler and java.compiler modules are to be converted. Use -Dtarget.jdk.ver=14 to automate this, or type a version in now (for example: 11): + + + + Aborted (no version entered) + + + + + Using VM at: ${target.jdk} + + + + You need to specify the JDK9+ jdk whose jdk.compiler and java.compiler modules are to be converted. Run ant with -Dtarget.jdk=/full/path/here to automate this, or type the path in now (for example: /Library/JavaVirtualMachines/jdk-14.jdk/Contents/Home): + + + + + + + + + + This tool converts javac as stored in jmods of JDK distributions; JDK8 and below doesn't ship like that, and you don't need this for 8 and below. + + + + ${target.javac.version.full} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <ivy-module version="2.0"> + <info organisation="net.java.openjdk.custom" module="javac${target.javac.shortversion}" revision="${target.javac.version}" publication="${target.javac.pubstamp}"> + <license name="GNU General Public License v2 with Classpath Exception" url="https://openjdk.java.net/legal/gplv2+ce.html" /> + <description homepage="https://openjdk.java.net" /> + </info> + <configurations> + <conf name="runtime" /> + </configurations> + <publications> + <artifact name="javac${target.javac.shortversion}-java.compiler" conf="runtime" url="https://projectlombok.org/ivyrepo/langtools/javac${target.javac.version}-java.compiler.jar" /> + <artifact name="javac${target.javac.shortversion}-jdk.compiler" conf="runtime" url="https://projectlombok.org/ivyrepo/langtools/javac${target.javac.version}-jdk.compiler.jar" /> + </publications> +</ivy-module> + File build/javac${target.javac.version}-java.compiler.jar and build/javac${target.javac.version}-jdk.compiler.jar are available for upload; custom ivy target made as GAV net.java.openjdk.custom::javac${target.javac.shortversion}::${target.javac.version} + + diff --git a/buildScripts/compile.ant.xml b/buildScripts/compile.ant.xml new file mode 100644 index 00000000..5baf50c3 --- /dev/null +++ b/buildScripts/compile.ant.xml @@ -0,0 +1,309 @@ + + + +This buildfile is part of projectlombok.org. It takes care of compiling and building lombok itself. + + + + + + + + + + + + + + + + + + + Lombok version: ${lombok.version} (${lombok.fullversion}) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lombok.launch.AnnotationProcessorHider$AnnotationProcessor +lombok.launch.AnnotationProcessorHider$ClaimingProcessor + + lombok.launch.AnnotationProcessorHider$AnnotationProcessor,isolating +lombok.launch.AnnotationProcessorHider$ClaimingProcessor,isolating + + + + + + + + + + + + + + + + + + + + + + + ${release.timestamp} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildScripts/create-eclipse-project.ant.xml b/buildScripts/create-eclipse-project.ant.xml new file mode 100644 index 00000000..513ffe8f --- /dev/null +++ b/buildScripts/create-eclipse-project.ant.xml @@ -0,0 +1,212 @@ + + + +This buildfile is part of projectlombok.org. It creates the infrastructure needed to develop lombok on eclipse. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildScripts/create-intellij-project.ant.xml b/buildScripts/create-intellij-project.ant.xml new file mode 100644 index 00000000..865e8971 --- /dev/null +++ b/buildScripts/create-intellij-project.ant.xml @@ -0,0 +1,58 @@ + + + +This buildfile is part of projectlombok.org. It creates the infrastructure needed to develop lombok on intellij. + + + + ** WARNING ** The core lombok contributors all use eclipse to develop lombok. This script will attempt to set up your lombok directory up as intellij project; whether can be used in a modern intellij is currently unknown. Please do continue, but be aware that trying to work on lombok from intellij may run into problems. If you want to adopt 'work on lombok via intellij' as a task, we're open to it! + NOT IMPLEMENTED: The project should optimally be configured as a java1.6, using the rt.jar in lib/openjdk6_rt.jar as boot basis, to ensure lombok remains 1.6 compatible. + NOT IMPLEMENTED: Ability to run tests targeted at a specific jvm/javac/ecj/eclipse release; the relevant entrypoint test classes are lombok.RunBaseAndJavacTests and lombok.RunEclipseTests - you can run the eclipse tests even on intellij; an eclipse installation is not required. + Press return to continue + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildScripts/eclipse-debug-target.template b/buildScripts/eclipse-debug-target.template deleted file mode 100644 index 78e01575..00000000 --- a/buildScripts/eclipse-debug-target.template +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/buildScripts/eclipse-p2.ant.xml b/buildScripts/eclipse-p2.ant.xml index db33b674..75f6c4eb 100644 --- a/buildScripts/eclipse-p2.ant.xml +++ b/buildScripts/eclipse-p2.ant.xml @@ -19,25 +19,23 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> - + This buildfile is part of projectlombok.org. It is responsible for building the eclipse P2 update site. - - - + - - - - + + + public class Epoch {public static void main(String[] args) {System.out.print(System.currentTimeMillis());}} + + - - + @@ -111,10 +109,25 @@ This buildfile is part of projectlombok.org. It is responsible for building the - - - public class Epoch {public static void main(String[] args) {System.out.print(System.currentTimeMillis());}} - - + + + + + + + + + diff --git a/buildScripts/eclipse-run-tests.template b/buildScripts/eclipse-run-tests.template deleted file mode 100644 index 0c00c236..00000000 --- a/buildScripts/eclipse-run-tests.template +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/buildScripts/info.ant.xml b/buildScripts/info.ant.xml new file mode 100644 index 00000000..fe6e0ee3 --- /dev/null +++ b/buildScripts/info.ant.xml @@ -0,0 +1,311 @@ + + + + +Dear contributor, + +For full instructions and information on what this project contains, run: + + > ant help + +If you want to get started quickly: + +1. Run `ant eclipse`. +2. Start up eclipse (https://www.eclipse.org/). +3. In the menu: File > Import... > Existing Project Into Workspace +4. Browse to this directory and import it: + (${basedir}) +5. In eclipse: Run > Debug configurations... > + then pick one of the configs named `Lombok test`. +6. Run `ant dist`. + +Have fun! + + + + +Just want to get started quickly? Run: + + > ant quickstart + +--- + +Lombok is specced to run on a wide array of underlying platforms: + +* Any JVM from 1.6 up to the upcoming next official release. +* Javac, from 1.6 up to the upcoming next official release. +* ECJ, from ecj 4.4.2 (2015/java8) up to the upcoming next official release. +* Eclipse, from eclipse-oxygen up to the upcoming next official release. + +The build is a little more complicated to cater to these requirements. + +This build script can perform the following tasks: +* IDE + Create project files so that you can work on lombok in eclipse or intellij. + Includes creating debuggable test targets. +* compile + Turn java files into class files. +* test + Run the tests against the various combinations of VM, Javac, eclipse and ecj + we support, including finding suitable VMs to run them on. +* packaging + Create the lombok 'everything' jar, that can serve as eclipse agent, as + installer, as library you include on the classpath with javac, and which + does not inject its transitive dependencies into your project namespace. +* website + Builds the website and documentation (projectlombok.org) from templates, + including creating the version history page and changelog, and deploying + builds to the website (and the maven repo hosted there). +* p2 + We host an experimental eclipse marketplace installer. + +For more info on any of these sections, run for example `ant help.IDE`. + +If you're new to lombok, you should start with `ant help.IDE`, +then move on to `ant help.test`. + + + + +We strongly suggest you use eclipse to develop lombok. +Experimentally, developing with intellij is possible as well. + +IDE support consists of two features: +1. Generate project files so that this directory can be imported as project. +2. Generate debug/run launch files so you can debug lombok in your IDE. + + > ant eclipse + > ant intellij + +These commands generate project files and download all dependencies required +to develop Project Lombok in the named IDE. Run these commands first, then +import this directory as project in your IDE. + + > ant eclipse.testtarget.eclipse + > ant eclipse.testtarget.ecj + > ant eclipse.testtarget.javac + +These 3 commands generate launch targets (these appear in your debug menu), +for testing the stated platform (eclipse, ecj, or javac) and will ask you +which version of the VM and the relevant platform are to be targeted by +these tests. Note that `ant eclipse` already generates default test targets, +you don't need these unless you're specifically testing lombok behaviour on +some specific version of the JVM or a target platform. + +NB: No debug/launch targets are currently generated for intellij. +Got the know how? We'd love a contribution! + + + + +The build compilation system is self contained and generally invoked by the +other jobs this build script can do; you rarely need to mess with it. + +The compilation is quite complicated; parts of lombok are injected into +for example eclipse at runtime via an agent mechanism. To produce the bytecode +that is to be injected, we need to compile against various different versions +of the core java libraries as well as eclipse/ecj. To make this process smooth +and fast, lombok has a 'stubs' concept: We have signature-only versions of +various classes of other libraries. We compile these first, then we compile +the rest of lombok with these stub classes on the classpath, and then we +package lombok without the stubs. + +Various bits of lombok are targeted at different versions, and therefore, +different parts of lombok are compiled with different `-release` targets. + + > ant compile + +Compiles lombok itself + + > ant compile.support + +Compiles code that isn't part of the lombok distribution, but which is used +for other jobs; For example, eclipse debug target generation, and fetching +the current lombok stable release version number on offer at +the projectlombok.org website involve java code. + + + + +Lombok is shipped as an 'everything' jar; it is a stand-alone java app, +with both a GUI and a command line interface, it's an agent, it's an +annotation processor, and it's a module. + +In addition, lombok is a compile-time only dependency, designed to be included +in every project a lombok user has. Therefore, we don't want any of the +lombok classes that you aren't meant to use directly to be visible, +showing up in auto-complete dialogs. Starting with JDK9, the module system's +'export' feature does a lot of this, but we also want to avoid contaminating +things on JDK8 and below. As a consequence, lombok uses a classloader system, +and most classes are included in the jar with a different name, not as +.class files, thus avoiding contaminating the namespace. + +The packaging targets take care of setting up the file rename as well as +registering all the various manifest and file entries needed so that lombok +can be an everything jar. + + > ant dist + +packages the lombok build into a single jar. + + > ant maven + > ant maven.publish + +'maven' packages the lombok build ready to upload to mavencentral (sonatype). +'maven.publish' also sends this via the lombok server to oss.sonatype.org. + + + + + + +Lombok tests need to be run against a targeted platform. + + > ant test.javacCurrent + > ant test.javac6 + > ant test.javac8 + > ant test.javac11 + > ant test.javac14 + +This runs the test suite that tests lombok on javac, as well as testing +the delombok feature. + +`javacCurrent` runs the tests on the JVM running this build: ${ant.java.version} + +`javac6` and `javac8` are run on the JVM running this build, by downloading +the complete java runtime classes from those versions, including javac, and +using module limits to exclude your VM's own javac. + +You _DO NOT_ need an installed JDK1.6 or JDK1.8 to run these. + +`javac11`, `javac14`, etc require that you have a JDK of that version +installed on your system. The build will automatically find such a JDK in most +cases; alternatively, the system will ask you to provide a path to them. +The tests are then run by invoking that VM to run them. + +You can force a particular VM by making a file named `jvm.locations`, and putting +in it, for example: + + j11 = /Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home + +Or just enter the path your VM installation when prompted, and the build will +automatically create this file for you to remember your choice. + + > ant test.eclipse-oxygen + > ant test.eclipse-202006 + +This runs the test suite that tests lombok on eclipse/ecj. + +The tests are run on your current VM (${ant.java.version}), fetching +the relevant bits of the chosen eclipse release to test against. + + > ant test + +Runs the 'default' targets for all supported platforms. This should catch +most problems. + + > ant test.broad + +Runs tests against a selection of versions designed to catch virtually all +problems. Doesn't quite test _every_ supported combination. + + > ant test.compile + +Compiles the test suite; generally invoked by the other test targets; +you don't need to explicitly invoke this yourself. + + + + +This build also builds the website, which is a static site generated via +freemarker templates. Parts of the site build also involve other custom +software, such as building the 'all available versions' page by checking +the available versions on the live website, compiling markdown +(as used by the changelog) into html, and generated color-coded syntax +in HTML for the example snippets. + + > ant changelog.build + +Turns the changelog at doc/changelog.markdown into +build/website/changelog.html. + + > ant website.build + > ant website.pack + > ant website.publish + +'build' Builds the website (by for example applying freemarker templates) into +build/website. +'pack' bzips this up, ready to ship to the server. +'publish' sends this to the server and runs a script to deploy. + + > ant website.open + + First builds the website, then hosts it locally and opens it in your browser so + you can see the website in its full, template-applied form. + + > ant latest-changes.build + +Makes a changelog variant that lists only the newest changes; it is included +in the distribution for convenience. + + > ant javadoc.build + > ant javadoc.pack + > ant javadoc.publish + +'build' Builds the javadoc into build/api. +'pack' bzips this up, ready to ship to the server. +'publish' sends this to the server and runs a script to deploy. + + > ant edge.pack + > ant edge.publish + +'pack' creates a bzip with all relevant files needed to deploy a new edge +release to the server: A fresh build of the lombok everything jar, plus the +maven repo update so that the edge release can be fetched as a maven dep, +and an update to the download-edge page listing the latest changes included +in the edge release. + +'publish' sends this to the server, runs a script server-side to deploy the +content, and updates a git tag on success. + + + + +This is still an experimental feature. + +We ship lombok as an eclipse plugin. The plugin isn't much of a plugin; the +install script of the plugin fulfills the same role as lombok's installer +(which is: add a line configuring lombok as an agent during eclipse bootup), +and the uninstall script removes it. + + > ant eclipsep2.build + > ant eclipsep2.pack + > ant eclipsep2.publish + +'build' generates the various files required to appear as an eclipse plugin, +and makes the jar(s). +'pack' makes a bzip ready to ship to a server. +'publish' ships it and runs a script server-side to put these files in the +right place; requires SSH access to the server. + + diff --git a/buildScripts/ivy-repo/net.java.openjdk.custom-javac11-11_2018-09-25.xml b/buildScripts/ivy-repo/net.java.openjdk.custom-javac11-11_2018-09-25.xml new file mode 100644 index 00000000..67b594da --- /dev/null +++ b/buildScripts/ivy-repo/net.java.openjdk.custom-javac11-11_2018-09-25.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/buildScripts/ivy-repo/net.java.openjdk.custom-javac13-13_2019-09-17.xml b/buildScripts/ivy-repo/net.java.openjdk.custom-javac13-13_2019-09-17.xml new file mode 100644 index 00000000..af861d7e --- /dev/null +++ b/buildScripts/ivy-repo/net.java.openjdk.custom-javac13-13_2019-09-17.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/buildScripts/ivy-repo/net.java.openjdk.custom-javac14-14-ea_2020-03-17.xml b/buildScripts/ivy-repo/net.java.openjdk.custom-javac14-14-ea_2020-03-17.xml new file mode 100644 index 00000000..175de028 --- /dev/null +++ b/buildScripts/ivy-repo/net.java.openjdk.custom-javac14-14-ea_2020-03-17.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/buildScripts/ivy-repo/net.java.openjdk.custom-javac8-1.8.0.xml b/buildScripts/ivy-repo/net.java.openjdk.custom-javac8-1.8.0.xml new file mode 100644 index 00000000..f02df135 --- /dev/null +++ b/buildScripts/ivy-repo/net.java.openjdk.custom-javac8-1.8.0.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.200.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.200.xml deleted file mode 100644 index 077f4f47..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.200.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.300.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.300.xml deleted file mode 100644 index f4002ee8..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.300.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.7.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.7.0.xml deleted file mode 100644 index b1ddf043..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.7.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.8.100.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.8.100.xml deleted file mode 100644 index eac7fe7b..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.8.100.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.runtime-3.6.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.runtime-3.6.0.xml deleted file mode 100644 index a5fe9784..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-core.runtime-3.6.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.runtime-3.9.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.runtime-3.9.0.xml deleted file mode 100644 index 0e06d062..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-core.runtime-3.9.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-ecj-3.6.2.xml b/buildScripts/ivy-repo/org.eclipse.custom-ecj-3.6.2.xml deleted file mode 100644 index 7da4c2ce..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-ecj-3.6.2.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-ecj-4.3.1.xml b/buildScripts/ivy-repo/org.eclipse.custom-ecj-4.3.1.xml deleted file mode 100644 index 8d0a8f0c..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-ecj-4.3.1.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-ecj-I20140430.xml b/buildScripts/ivy-repo/org.eclipse.custom-ecj-I20140430.xml deleted file mode 100644 index 193f8a27..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-ecj-I20140430.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-equinox.common-3.6.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-equinox.common-3.6.0.xml deleted file mode 100644 index 69d18ae4..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-equinox.common-3.6.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/buildScripts/ivy-repo/org.eclipse.custom-equinox.common-3.6.200.xml b/buildScripts/ivy-repo/org.eclipse.custom-equinox.common-3.6.200.xml deleted file mode 100644 index d0a128ec..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-equinox.common-3.6.200.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/buildScripts/ivy-repo/org.eclipse.custom-jdt.core-3.6.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-jdt.core-3.6.0.xml deleted file mode 100644 index 2c46df18..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-jdt.core-3.6.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-jdt.core-3.9.1.xml b/buildScripts/ivy-repo/org.eclipse.custom-jdt.core-3.9.1.xml deleted file mode 100644 index 946aa65a..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-jdt.core-3.9.1.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-jdt.ui-3.6.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-jdt.ui-3.6.0.xml deleted file mode 100644 index 6dcf54f0..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-jdt.ui-3.6.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-jdt.ui-3.9.1.xml b/buildScripts/ivy-repo/org.eclipse.custom-jdt.ui-3.9.1.xml deleted file mode 100644 index e57bad7a..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-jdt.ui-3.9.1.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-osgi-3.6.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-osgi-3.6.0.xml deleted file mode 100644 index 7cca0e05..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-osgi-3.6.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy-repo/org.eclipse.custom-osgi-3.9.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-osgi-3.9.0.xml deleted file mode 100644 index 83e009eb..00000000 --- a/buildScripts/ivy-repo/org.eclipse.custom-osgi-3.9.0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml index 1d8fc26b..3dfbde7e 100644 --- a/buildScripts/ivy.xml +++ b/buildScripts/ivy.xml @@ -1,64 +1,64 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -66,6 +66,41 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildScripts/ivysettings.xml b/buildScripts/ivysettings.xml index bafdc801..765dad02 100644 --- a/buildScripts/ivysettings.xml +++ b/buildScripts/ivysettings.xml @@ -4,6 +4,7 @@ + diff --git a/buildScripts/mapstructBinding.ant.xml b/buildScripts/mapstructBinding.ant.xml new file mode 100644 index 00000000..c59b84da --- /dev/null +++ b/buildScripts/mapstructBinding.ant.xml @@ -0,0 +1,125 @@ + + + +This buildfile is part of projectlombok.org. It builds the mapstruct-lombok binding; we think the +version on mavencentral is the last version that is ever needed; the code itself is trivial and +exists as a separate dependency solely because it is itself dependent on both lombok and mapstruct. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lombok.mapstruct.NotifierHider$AstModificationNotifier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mvn is not on your path and/or MAVEN_HOME is not set. Add mvn to your path or set MAVEN_HOME to continue. + + + + + + diff --git a/buildScripts/maven.ant.xml b/buildScripts/maven.ant.xml new file mode 100644 index 00000000..dcba2ccb --- /dev/null +++ b/buildScripts/maven.ant.xml @@ -0,0 +1,126 @@ + + + +This buildfile is part of projectlombok.org. It makes maven-compatible repositories. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The artifact has been published to staging. Now go to https://oss.sonatype.org/ and log in as Reinier, then doublecheck if all is well and 'release' it. + + + + + + + + + + + + + + + + + + + + + + + + mvn is not on your path and/or MAVEN_HOME is not set. Add mvn to your path or set MAVEN_HOME to continue. + + + + + + diff --git a/buildScripts/setup.ant.xml b/buildScripts/setup.ant.xml new file mode 100644 index 00000000..9b96240d --- /dev/null +++ b/buildScripts/setup.ant.xml @@ -0,0 +1,188 @@ + + + +This buildfile is part of projectlombok.org. It sets up the build itself. + + + + + + + + + + + + + + + + + Your ssh.configuration file is corrupted; delete it and rerun this script. + + + + + + + + + + + + + + + The keyfile configured in your ${ssh.configuration.file} file does not exist. + + + + + + + + + + + + + + + + Aborted + + File ${ssh.keyfile} does not exist + + + + + + + + Your connection info has been written to ${ssh.configuration.file} and will be remembered for future invocations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A new version of ivyplusplus was required and has been downloaded. Rerun the script to continue. + + + + + + + + + + + To ensure stable builds and avoid accessing API that was not available in JDK6, most of lombok is set up to build against OpenJDK6's runtime, which will now be downloaded... + + + + + + To test java8, we need a java8 runtime, which will now be downloaded... + + + + + + + + Supply ant with -Ddeps.conf=confname to pick the configuration you want to fetch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ant needs to be at least v1.10.0 or higher to build lombok. Your version is: ${ant.version} + + + + + lombok must be compiled on jdk11 or later. Your version is: ${ant.java.version} + + + + + diff --git a/buildScripts/tests.ant.xml b/buildScripts/tests.ant.xml new file mode 100644 index 00000000..cb840048 --- /dev/null +++ b/buildScripts/tests.ant.xml @@ -0,0 +1,181 @@ + + + +This buildfile is part of projectlombok.org. It takes care of compiling and running tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + run ecj11 with a test file to confirm agent injection works: OK + + + + --add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED + + --limit-modules java.base,jdk.unsupported + + + + + + + + + + + Running TestJavac on JVM${ant.java.version}, with lowest supported javac: 1.6. + + + + + + + + + + + + + + + + Running TestJavac on JVM${ant.java.version}, with javac: 1.8. + + + + + + + + + + + + + + + + + + + Running TestJavac with JVM ${jvm.loc.@{version}}. + + + + + + + + + + + + + + + + + + + + + + + + Running TestJavac on JVM${ant.java.version}, with the javac built into your VM distributon. + + + + + + + + + + + + + + + + Running TestEclipse on eclipse-@{version} on JVM${ant.java.version}. + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildScripts/vm-finder.ant.xml b/buildScripts/vm-finder.ant.xml new file mode 100644 index 00000000..2b2c4c4c --- /dev/null +++ b/buildScripts/vm-finder.ant.xml @@ -0,0 +1,191 @@ + + + +This buildfile is part of projectlombok.org. It contains platform specific code to find installed JVMs. + + + + + + + + + + + + + + + + + + + + + + + + + + + . + +ERROR: You explicitly specified the home of JVM${find-vm.version} as: ${jvm.loc} in the ${jvm.locations.file} file. +However, ${jvm.loc}/bin/${exe.java} does not exist or is not executable. Please fix the entry in jvm.locations, or delete it +and rerun the build; this build is capable of finding VMs automatically on many platforms. + + + + + Set property find-vm.version first + + + + + + + + + + + + + Set property find-vm.version first + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set property find-vm.version first + A JVM${find-vm.version} is required to run the request tests. + this script can automatically find VMs on mac and windows but did not find a suitable VM. + + + + + aborted + . + +ERROR: That does not appear to be a valid location; ${jvm.loc}/bin/${exe.java} should exist. + + + + + + + + + That does not appear to be a valid JVM${find-vm.version} - perhaps it isn't the right version? + + + + + + + + + + + Your choice of VM has been written to ${jvm.locations.file} and will be remembered for future invocations. + + + + + + + + + JVM ${find-vm.version} cannot be found + + + + + + + + + + + + + + + diff --git a/buildScripts/website.ant.xml b/buildScripts/website.ant.xml index b6212b37..730b79c2 100644 --- a/buildScripts/website.ant.xml +++ b/buildScripts/website.ant.xml @@ -1,5 +1,5 @@ + + - - + + + - + - - + + + - - Supply lombok.version + + Live version: ${lombok.version.live} + Live full versionstring : ${lombok.fullversion.live} - - Version: ${lombok.version} - Full: ${lombok.fullversion} - - - - Supply lombok.fullversion - - - - - - - - - - - - - + - - - + + + + - - - - - - - - - - + + + - + - + - - + + + @@ -144,49 +103,87 @@ such as applying the templates to produce the website, converting the changelog - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - + + - + + + + + + + + + + + + + + - - + - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ssh.username and ssh.keyfile should be set. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -304,13 +211,12 @@ such as applying the templates to produce the website, converting the changelog write your own plugins, the other packages are what you're looking for. ]]> - + -
Lombok - ]]>v${lombok.version}
Copyright © 2009-${javadoc.year} The Project Lombok Authors, licensed under the MIT licence.]]> @@ -346,4 +252,129 @@ such as applying the templates to produce the website, converting the changelog
+ + + + + + + File dist/javadoc.tar.bz2 is available + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index f56ae524..91fdd6a5 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,15 +2,22 @@ Lombok Changelog ---------------- ### v1.18.13 "Edgy Guinea Pig" +* PERFORMANCE: Several performance improvements during parsing/compilation, both using javac and Eclipse. Thanks __@Rawi01__! +* PERFORMANCE: The generated equals method will first compare primitives, then primitive wrappers and then reference fields. Manual re-ordering is possible using `@Include(rank=n)`. [Pull Request #2485](https://github.com/rzwitserloot/lombok/pull/2485), [Issue #1543](https://github.com/rzwitserloot/lombok/issues/1543) +* IMPROBABLE BREAKING CHANGE: The generated hashcode has changed for classes that include both primitive fields and reference fields. +* PLATFORM: Added support for compiling projects with OpenJ9 [Pull Request #2437](https://github.com/rzwitserloot/lombok/pull/2437) * BREAKING CHANGE: mapstruct users should now add a dependency to lombok-mapstruct-binding. This solves compiling modules with lombok (and mapstruct). * FEATURE: Similar to `@Builder`, you can now configure a `@SuperBuilder`'s 'setter' prefixes via `@SuperBuilder(setterPrefix = "set")` for example. We still discourage doing this. [Pull Request #2357](https://github.com/rzwitserloot/lombok/pull/2357). * FEATURE: If using `@Synchronized("lockVar")`, if `lockVar` is referring to a static field, the code lombok generates no longer causes a warning about accessing a static entity incorrectly. [Issue #678](https://github.com/rzwitserloot/lombok/issues/678) +* BUGFIX: Delombok print the first `this` parameter. [Issue #2444](https://github.com/rzwitserloot/lombok/issues/2444) * BUGFIX: Using `val` in combination with values whose generics include wildcards that reference themselves would cause a `StackOverflowError` in javac. [Issue #2358](https://github.com/rzwitserloot/lombok/issues/2358). * BUGFIX: Using `@SuperBuilder` on a class that has some fairly convoluted generics usage would fail with 'Wrong number of type arguments'. [Issue #2359](https://github.com/rzwitserloot/lombok/issues/2359) [Pull Request #2362](https://github.com/rzwitserloot/lombok/pull/2362) * BUGFIX: Various lombok annotations on classes nested inside enums or interfaces would cause errors in eclipse. [Issue #2369](https://github.com/rzwitserloot/lombok/issues/2369) * BUGFIX: Trying to add `@ExtensionMethod`s with exactly 2 arguments would fail in eclipse. [Issue #1441](https://github.com/rzwitserloot/lombok/issues/1441) [Pull Request #2376](https://github.com/rzwitserloot/lombok/pull/2376) thanks to __@Rawi01__. +* BUGFIX: Javac sets incorrect annotated type on with methods. [Issue #2463](https://github.com/rzwitserloot/lombok/issues/2463) * FEATURE: `@Jacksonized` on a `@Builder` or `@SuperBuilder` will configure [Jackson](https://github.com/FasterXML/jackson) to use this builder when deserializing. [Pull Request #2387](https://github.com/rzwitserloot/lombok/pull/2387) thanks to __@JanRieke__. [@Jacksonized documentation](https://projectlombok.org/features/experimental/Jacksonized). + ### v1.18.12 (February 1st, 2020) * PLATFORM: Support for JDK13 (including `yield` in switch expressions, as well as delombok having a nicer style for arrow-style switch blocks, and text blocks). * PLATFORM: Support for JDK14 (including `pattern match` instanceof expressions). diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index 4ca3da65..64294e4b 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -32,8 +32,8 @@ import java.lang.annotation.Target; * that contains a member which is annotated with {@code @Builder}. *

* If a member is annotated, it must be either a constructor or a method. If a class is annotated, - * then a private constructor is generated with all fields as arguments - * (as if {@code @AllArgsConstructor(access = AccessLevel.PRIVATE)} is present + * then a package-private constructor is generated with all fields as arguments + * (as if {@code @AllArgsConstructor(access = AccessLevel.PACKAGE)} is present * on the class), and it is as if this constructor has been annotated with {@code @Builder} instead. * Note that this constructor is only generated if you haven't written any constructors and also haven't * added any explicit {@code @XArgsConstructor} annotations. In those cases, lombok will assume an all-args diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 46cf7412..01a4b576 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -89,6 +89,13 @@ public class ConfigurationKeys { */ public static final ConfigurationKey ADD_FINDBUGS_SUPPRESSWARNINGS_ANNOTATIONS = new ConfigurationKey("lombok.extern.findbugs.addSuppressFBWarnings", "Generate @edu.umd.cs.findbugs.annotations.SuppressFBWarnings on all generated code (default: false).") {}; + /** + * lombok configuration: {@code lombok.addSuppressWarnings} = {@code true} | {@code false}. + * + * If {@code true}, lombok generates {@code @java.lang.SuppressWarnings("all")} on all fields, methods, and types that are generated. + */ + public static final ConfigurationKey ADD_SUPPRESSWARNINGS_ANNOTATIONS = new ConfigurationKey("lombok.addSuppressWarnings", "Generate @java.lang.SuppressWarnings(\"all\") on all generated code (default: true).") {}; + /** * lombok configuration: {@code lombok.addNullAnnotations = }one of: [{@code none}, {@code javax}, {@code eclipse}, {@code jetbrains}, {@code netbeans}, {@code androidx}, {@code android.support}, {@code checkerframework}, {@code findbugs}, {@code spring}, {@code JML}, or a custom set of fully qualified annotation types]. * @@ -133,7 +140,7 @@ public class ConfigurationKeys { * NB: GWT projects, and probably android projects, should explicitly set this key to {@code true} for the entire project. * *
- * BREAKING CHANGE: Starting with lombok v1.16.20, defaults to {@code false} instead of {@code true}, as {@code @ConstructorProperties} requires extra modules in JDK9. + * BREAKING CHANGE: Starting with lombok v1.16.20, defaults to {@code true} instead of {@code false}, as {@code @ConstructorProperties} requires extra modules in JDK9. * * @see ConfigurationKeys#ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES * @deprecated Since version 2.0, use {@link #ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES} instead. diff --git a/src/core/lombok/EqualsAndHashCode.java b/src/core/lombok/EqualsAndHashCode.java index e752165c..6805d214 100644 --- a/src/core/lombok/EqualsAndHashCode.java +++ b/src/core/lombok/EqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2020 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 @@ -122,5 +122,14 @@ public @interface EqualsAndHashCode { * @return If present, this method serves as replacement for the named field. */ String replaces() default ""; + + /** + * Higher ranks are considered first. Members of the same rank are considered in the order they appear in the source file. + * + * If not explicitly set, the {@code default} rank for primitives is 1000, and for primitive wrappers 800. + * + * @return ordering within the generating {@code equals} and {@code hashCode} methods; higher numbers are considered first. + */ + int rank() default 0; } } diff --git a/src/core/lombok/Singular.java b/src/core/lombok/Singular.java index 2ceaad58..08b53973 100644 --- a/src/core/lombok/Singular.java +++ b/src/core/lombok/Singular.java @@ -36,6 +36,6 @@ public @interface Singular { /** @return The singular name of this field. If it's a normal english plural, lombok will figure it out automatically. Otherwise, this parameter is mandatory. */ String value() default ""; - /** @return If true, the plural variant (which takes a collection and adds each element inside) will treat {@code null} as an empty collection, i.e. do nothing. If {@code false) (the default), it is null checked as if annotated with {@code @lombok.NonNull}. */ + /** @return If true, the plural variant (which takes a collection and adds each element inside) will treat {@code null} as an empty collection, i.e. do nothing. If {@code false} (the default), it is null checked as if annotated with {@code @lombok.NonNull}. */ boolean ignoreNullCollections() default false; } diff --git a/src/core/lombok/With.java b/src/core/lombok/With.java index 141d1fa6..417d8b31 100644 --- a/src/core/lombok/With.java +++ b/src/core/lombok/With.java @@ -26,8 +26,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import lombok.AccessLevel; - /** * Put on any field to make lombok build a 'with' - a withX method which produces a clone of this object (except for 1 field which gets a new value). *

diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index ce93a069..d4a92408 100644 --- a/src/core/lombok/core/AnnotationProcessor.java +++ b/src/core/lombok/core/AnnotationProcessor.java @@ -83,7 +83,12 @@ public class AnnotationProcessor extends AbstractProcessor { for (Class procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { try { - Field field = Permit.getField(procEnvClass, "delegate"); + Field field; + try { + field = Permit.getField(procEnvClass, "delegate"); + } catch (NoSuchFieldException e) { + field = Permit.getField(procEnvClass, "processingEnv"); + } Object delegate = field.get(procEnv); return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate); diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java index eec5abd8..78bb1fb5 100644 --- a/src/core/lombok/core/AnnotationValues.java +++ b/src/core/lombok/core/AnnotationValues.java @@ -411,6 +411,14 @@ public class AnnotationValues { List l = getActualExpressions(annotationMethodName); return l.isEmpty() ? null : l.get(0); } + + /** + * Returns the guessed value for the provided {@code annotationMethodName}. + */ + public Object getValueGuess(String annotationMethodName) { + AnnotationValue v = values.get(annotationMethodName); + return v == null || v.valueGuesses.isEmpty() ? null : v.valueGuesses.get(0); + } /** Generates an error message on the stated annotation value (you should only call this method if you know it's there!) */ public void setError(String annotationMethodName, String message) { diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java index e52cd5b3..abfc66a6 100644 --- a/src/core/lombok/core/LombokNode.java +++ b/src/core/lombok/core/LombokNode.java @@ -288,9 +288,23 @@ public abstract class LombokNode, L extends LombokNode 0) { + try { + copy = applyTransformations(original, fileName, diagnostics); + } catch (Exception e) { + diagnostics.addWarning(String.format("Error during the transformation of '%s'; no post-compilation has been applied", fileName)); + } } if (copy == null) { diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 94fd21d9..1c4437d7 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.regex.Pattern; import lombok.AllArgsConstructor; import lombok.ConfigurationKeys; @@ -76,7 +77,7 @@ public class HandlerUtil { return 43; } - public static final List NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, COPY_TO_SETTER_ANNOTATIONS, JACKSON_COPY_TO_BUILDER_ANNOTATIONS; + public static final List NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, COPY_TO_SETTER_ANNOTATIONS, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS, JACKSON_COPY_TO_BUILDER_ANNOTATIONS; static { NONNULL_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { "androidx.annotation.NonNull", @@ -312,10 +313,24 @@ public class HandlerUtil { "org.netbeans.api.annotations.common.NullAllowed", })); COPY_TO_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { + "com.fasterxml.jackson.annotation.JacksonInject", + "com.fasterxml.jackson.annotation.JsonAlias", + "com.fasterxml.jackson.annotation.JsonFormat", + "com.fasterxml.jackson.annotation.JsonIgnore", + "com.fasterxml.jackson.annotation.JsonIgnoreProperties", "com.fasterxml.jackson.annotation.JsonProperty", "com.fasterxml.jackson.annotation.JsonSetter", + "com.fasterxml.jackson.annotation.JsonSubTypes", + "com.fasterxml.jackson.annotation.JsonTypeInfo", + "com.fasterxml.jackson.annotation.JsonView", + "com.fasterxml.jackson.databind.annotation.JsonDeserialize", + "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty", + })); + COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { + "com.fasterxml.jackson.annotation.JsonAnySetter", })); JACKSON_COPY_TO_BUILDER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { + "com.fasterxml.jackson.annotation.JsonAutoDetect", "com.fasterxml.jackson.annotation.JsonFormat", "com.fasterxml.jackson.annotation.JsonIgnoreProperties", "com.fasterxml.jackson.annotation.JsonIgnoreType", @@ -351,6 +366,7 @@ public class HandlerUtil { public static String autoSingularize(String plural) { return Singulars.autoSingularize(plural); } + public static void handleFlagUsage(LombokNode node, ConfigurationKey key, String featureName) { FlagUsageType fut = node.getAst().readConfiguration(key); @@ -728,4 +744,16 @@ public class HandlerUtil { } return b.toString(); } + + /** Matches any of the 8 primitive wrapper names, such as {@code Boolean}. */ + private static final Pattern PRIMITIVE_WRAPPER_TYPE_NAME_PATTERN = Pattern.compile("^(?:java\\.lang\\.)?(?:Boolean|Byte|Short|Integer|Long|Float|Double|Character)$"); + + public static int defaultEqualsAndHashcodeIncludeRank(String typeName) { + // Modification in this code should be documented + // 1. In the changelog this should be marked as an INPROBABLE BREAKING CHANGE, since the hashcode will change + // 2. In the javadoc of EqualsAndHashcode.Include#rank + if (JavaIdentifiers.isPrimitive(typeName)) return 1000; + if (PRIMITIVE_WRAPPER_TYPE_NAME_PATTERN.matcher(typeName).matches()) return 800; + return 0; + } } diff --git a/src/core/lombok/core/handlers/InclusionExclusionUtils.java b/src/core/lombok/core/handlers/InclusionExclusionUtils.java index 368b51fc..0aa6c47b 100644 --- a/src/core/lombok/core/handlers/InclusionExclusionUtils.java +++ b/src/core/lombok/core/handlers/InclusionExclusionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2020 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 @@ -76,11 +76,13 @@ public class InclusionExclusionUtils { private final L node; private final I inc; private final boolean defaultInclude; + private final boolean explicitRank; - public Included(L node, I inc, boolean defaultInclude) { + public Included(L node, I inc, boolean defaultInclude, boolean explicitRank) { this.node = node; this.inc = inc; this.defaultInclude = defaultInclude; + this.explicitRank = explicitRank; } public L getNode() { @@ -94,6 +96,10 @@ public class InclusionExclusionUtils { public boolean isDefaultInclude() { return defaultInclude; } + + public boolean hasExplicitRank() { + return explicitRank; + } } private static String innerAnnName(Class type) { @@ -106,7 +112,7 @@ public class InclusionExclusionUtils { return name; } - public static , L extends LombokNode, N, I extends Annotation> List> handleIncludeExcludeMarking(Class inclType, String replaceName, Class exclType, LombokNode typeNode, AnnotationValues annotation, LombokNode annotationNode, boolean includeTransient) { + private static , L extends LombokNode, N, I extends Annotation> List> handleIncludeExcludeMarking(Class inclType, String replaceName, Class exclType, LombokNode typeNode, AnnotationValues annotation, LombokNode annotationNode, boolean includeTransient) { List oldExcludes = (annotation != null && annotation.isExplicit("exclude")) ? annotation.getAsStringList("exclude") : null; List oldIncludes = (annotation != null && annotation.isExplicit("of")) ? annotation.getAsStringList("of") : null; @@ -118,9 +124,6 @@ public class InclusionExclusionUtils { 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."); @@ -134,7 +137,7 @@ public class InclusionExclusionUtils { if (markExclude || markInclude != null) memberAnnotationMode = true; if (markInclude != null && markExclude) { - child.addError("@" + exclTypeName + " and @" + inclTypeName + " are mutually exclusive; the @Include annotation will be ignored"); + child.addError("@" + innerAnnName(exclType) + " and @" + innerAnnName(inclType) + " are mutually exclusive; the @Include annotation will be ignored"); markInclude = null; } @@ -157,20 +160,20 @@ public class InclusionExclusionUtils { 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"); + child.addError("Methods included with @" + innerAnnName(inclType) + " 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(child, inc, false)); + members.add(new Included(child, inc, false, markInclude.isExplicit("rank"))); continue; } if (onlyExplicitlyIncluded) continue; if (oldIncludes != null) { - if (child.getKind() == Kind.FIELD && oldIncludes.contains(name)) members.add(new Included(child, null, false)); + if (child.getKind() == Kind.FIELD && oldIncludes.contains(name)) members.add(new Included(child, null, false, false)); continue; } if (child.getKind() != Kind.FIELD) continue; @@ -178,7 +181,7 @@ public class InclusionExclusionUtils { if (child.isTransient() && !includeTransient) continue; if (name.startsWith("$")) continue; if (child.isEnumMember()) continue; - members.add(new Included(child, null, true)); + members.add(new Included(child, null, true, false)); } /* delete default-included fields with the same name as an explicit inclusion */ { @@ -207,22 +210,37 @@ public class InclusionExclusionUtils { @Override public int compare(Included a, Included 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 compareRankOrPosition(ra, rb, a.getNode(), b.getNode()); } }); return members; } public static , L extends LombokNode, N> List> handleEqualsAndHashCodeMarking(LombokNode typeNode, AnnotationValues annotation, LombokNode annotationNode) { - return handleIncludeExcludeMarking(EqualsAndHashCode.Include.class, "replaces", EqualsAndHashCode.Exclude.class, typeNode, annotation, annotationNode, false); + List> members = handleIncludeExcludeMarking(EqualsAndHashCode.Include.class, "replaces", EqualsAndHashCode.Exclude.class, typeNode, annotation, annotationNode, false); + + Collections.sort(members, new Comparator>() { + @Override public int compare(Included a, Included b) { + int ra = a.hasExplicitRank() ? a.getInc().rank() : HandlerUtil.defaultEqualsAndHashcodeIncludeRank(a.node.fieldOrMethodBaseType()); + int rb = b.hasExplicitRank() ? b.getInc().rank() : HandlerUtil.defaultEqualsAndHashcodeIncludeRank(b.node.fieldOrMethodBaseType()); + + return compareRankOrPosition(ra, rb, a.getNode(), b.getNode()); + } + }); + return members; + } + + private static , L extends LombokNode, N> int compareRankOrPosition(int ra, int rb, LombokNode nodeA, LombokNode nodeB) { + if (ra < rb) return +1; + if (ra > rb) return -1; + + int pa = nodeA.getStartPos(); + int pb = nodeB.getStartPos(); + + if (pa < pb) return -1; + if (pa > pb) return +1; + + return 0; } } diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index e724fb50..d53856af 100644 --- a/src/core/lombok/eclipse/EclipseAST.java +++ b/src/core/lombok/eclipse/EclipseAST.java @@ -318,6 +318,7 @@ public class EclipseAST extends AST { Field f = EcjReflectionCheck.typeReferenceAnnotations; if (f == null) return null; annss = (Annotation[][]) f.get(tr); + if (annss == null) return null; return annss[annss.length - 1]; } catch (Throwable t) { return null; @@ -349,7 +350,7 @@ public class EclipseAST extends AST { if (!changed) clearChanged(); } - private static boolean isComplete(CompilationUnitDeclaration unit) { + public static boolean isComplete(CompilationUnitDeclaration unit) { return (unit.bits & ASTNode.HasAllMethodBodies) != 0; } diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index 9db491f5..12e9ccdb 100644 --- a/src/core/lombok/eclipse/EclipseNode.java +++ b/src/core/lombok/eclipse/EclipseNode.java @@ -23,10 +23,6 @@ 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; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -36,11 +32,16 @@ import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.eclipse.handlers.EclipseHandlerUtil; + /** * Eclipse specific version of the LombokNode class. */ @@ -264,6 +265,39 @@ public class EclipseNode extends lombok.core.LombokNode transformationStates = Collections.synchronizedMap(new WeakHashMap()); static { String v = System.getProperty("lombok.histogram"); @@ -129,6 +133,30 @@ public class TransformEclipseAST { return existing; } + /** + * Check if lombok already handled the given AST. This method will return + * true once for diet mode and once for full mode. + * + * The reason for this is that Eclipse invokes the transform method multiple + * times during compilation and it is enough to transform it once and not + * repeat the whole thing over and over again. + * + * @param ast The AST node belonging to the compilation unit (java speak for a single source file). + * @return true if this AST was already handled by lombok. + */ + public static boolean alreadyTransformed(CompilationUnitDeclaration ast) { + State state = transformationStates.get(ast); + + if (state == State.FULL) return true; + if (state == State.DIET) { + if (!EclipseAST.isComplete(ast)) return true; + transformationStates.put(ast, State.FULL); + } else { + transformationStates.put(ast, State.DIET); + } + return false; + } + /** * This method is called immediately after Eclipse finishes building a CompilationUnitDeclaration, which is * the top-level AST node when Eclipse parses a source file. The signature is 'magic' - you should not @@ -144,6 +172,7 @@ public class TransformEclipseAST { if (disableLombok) return; if (Symbols.hasSymbol("lombok.disable")) return; + if (alreadyTransformed(ast)) return; // Do NOT abort if (ast.bits & ASTNode.HasAllMethodBodies) != 0 - that doesn't work. @@ -243,4 +272,9 @@ public class TransformEclipseAST { nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority)); } } + + private static enum State { + DIET, + FULL + } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 4df7a90b..6bfcf16e 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -26,6 +26,7 @@ import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.EclipseAugments.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.EclipseReflectiveMembers.*; +import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -48,6 +49,7 @@ import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; import org.eclipse.jdt.internal.compiler.ast.AssertStatement; +import org.eclipse.jdt.internal.compiler.ast.BinaryExpression; import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.CastExpression; import org.eclipse.jdt.internal.compiler.ast.CharLiteral; @@ -232,14 +234,7 @@ public class EclipseHandlerUtil { * @param typeRef A type reference to check. */ public static boolean typeMatches(Class type, EclipseNode node, TypeReference typeRef) { - if (typeRef == null || typeRef.getTypeName() == null || typeRef.getTypeName().length == 0) return false; - String lastPartA = new String(typeRef.getTypeName()[typeRef.getTypeName().length -1]); - String lastPartB = type.getSimpleName(); - if (!lastPartA.equals(lastPartB)) return false; - String typeName = toQualifiedName(typeRef.getTypeName()); - - TypeResolver resolver = new TypeResolver(node.getImportList()); - return resolver.typeMatches(node, type.getName(), typeName); + return typeMatches(type.getName(), node, typeRef); } /** @@ -253,7 +248,7 @@ public class EclipseHandlerUtil { char[][] tn = typeRef == null ? null : typeRef.getTypeName(); if (tn == null || tn.length == 0) return false; char[] lastPartA = tn[tn.length - 1]; - int lastIndex = type.lastIndexOf('.') + 1; + int lastIndex = Math.max(type.lastIndexOf('.'), type.lastIndexOf('$')) + 1; if (lastPartA.length != type.length() - lastIndex) return false; for (int i = 0; i < lastPartA.length; i++) if (lastPartA[i] != type.charAt(i + lastIndex)) return false; String typeName = toQualifiedName(tn); @@ -335,14 +330,16 @@ public class EclipseHandlerUtil { public static final Field STRING_LITERAL__LINE_NUMBER; public static final Field ANNOTATION__MEMBER_VALUE_PAIR_NAME; public static final Field TYPE_REFERENCE__ANNOTATIONS; - public static final Class INTERSECTION_BINDING; - public static final Field INTERSECTION_BINDING_TYPES; + public static final Class INTERSECTION_BINDING1, INTERSECTION_BINDING2; + public static final Field INTERSECTION_BINDING_TYPES1, INTERSECTION_BINDING_TYPES2; static { STRING_LITERAL__LINE_NUMBER = getField(StringLiteral.class, "lineNumber"); ANNOTATION__MEMBER_VALUE_PAIR_NAME = getField(Annotation.class, "memberValuePairName"); TYPE_REFERENCE__ANNOTATIONS = getField(TypeReference.class, "annotations"); - INTERSECTION_BINDING = getClass("org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18"); - INTERSECTION_BINDING_TYPES = INTERSECTION_BINDING == null ? null : getField(INTERSECTION_BINDING, "intersectingTypes"); + INTERSECTION_BINDING1 = getClass("org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18"); + INTERSECTION_BINDING2 = getClass("org.eclipse.jdt.internal.compiler.lookup.IntersectionCastTypeBinding"); + INTERSECTION_BINDING_TYPES1 = INTERSECTION_BINDING1 == null ? null : getField(INTERSECTION_BINDING1, "intersectingTypes"); + INTERSECTION_BINDING_TYPES2 = INTERSECTION_BINDING2 == null ? null : getField(INTERSECTION_BINDING2, "intersectingTypes"); } public static int reflectInt(Field f, Object o) { @@ -386,7 +383,7 @@ public class EclipseHandlerUtil { } } - private static Expression copyAnnotationMemberValue(Expression in) { + public static Expression copyAnnotationMemberValue(Expression in) { Expression out = copyAnnotationMemberValue0(in); out.constant = in.constant; return out; @@ -427,12 +424,11 @@ public class EclipseHandlerUtil { if (in instanceof SingleNameReference) { SingleNameReference snr = (SingleNameReference) in; - long p = (long) s << 32 | e; - return new SingleNameReference(snr.token, p); + return new SingleNameReference(snr.token, pos(in)); } if (in instanceof QualifiedNameReference) { QualifiedNameReference qnr = (QualifiedNameReference) in; - return new QualifiedNameReference(qnr.tokens, qnr.sourcePositions, s, e); + return new QualifiedNameReference(qnr.tokens, poss(in, qnr.tokens.length), s, e); } // class refs @@ -448,11 +444,22 @@ public class EclipseHandlerUtil { out.sourceEnd = e; out.bits = in.bits; out.implicitConversion = in.implicitConversion; - out.statementEnd = in.statementEnd; + out.statementEnd = e; out.expressions = copy; return out; } + if (in instanceof BinaryExpression) { + BinaryExpression be = (BinaryExpression) in; + BinaryExpression out = new BinaryExpression(be); + out.left = copyAnnotationMemberValue(be.left); + out.right = copyAnnotationMemberValue(be.right); + out.sourceStart = s; + out.sourceEnd = e; + out.statementEnd = e; + return out; + } + return in; } @@ -660,9 +667,11 @@ public class EclipseHandlerUtil { Annotation[][] b = new Annotation[a.length][]; for (int i = 0; i < a.length; i++) { - b[i] = new Annotation[a[i].length]; - for (int j = 0 ; j < a[i].length; j++) { - b[i][j] = copyAnnotation(a[i][j], a[i][j]); + if (a[i] != null) { + b[i] = new Annotation[a[i].length]; + for (int j = 0 ; j < a[i].length; j++) { + b[i][j] = copyAnnotation(a[i][j], a[i][j]); + } } } @@ -817,6 +826,20 @@ public class EclipseHandlerUtil { * Searches the given field node for annotations that are specifically intentioned to be copied to the setter. */ public static Annotation[] findCopyableToSetterAnnotations(EclipseNode node) { + return findAnnotationsInList(node, COPY_TO_SETTER_ANNOTATIONS); + } + + /** + * Searches the given field node for annotations that are specifically intentioned to be copied to the builder's singular method. + */ + public static Annotation[] findCopyableToBuilderSingularSetterAnnotations(EclipseNode node) { + return findAnnotationsInList(node, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS); + } + + /** + * Searches the given field node for annotations that are in the given list, and returns those. + */ + private static Annotation[] findAnnotationsInList(EclipseNode node, java.util.List annotationsToFind) { AbstractVariableDeclaration avd = (AbstractVariableDeclaration) node.get(); if (avd.annotations == null) return EMPTY_ANNOTATIONS_ARRAY; List result = new ArrayList(); @@ -824,7 +847,7 @@ public class EclipseHandlerUtil { for (Annotation annotation : avd.annotations) { TypeReference typeRef = annotation.type; if (typeRef != null && typeRef.getTypeName() != null) { - for (String bn : COPY_TO_SETTER_ANNOTATIONS) if (typeMatches(bn, node, typeRef)) { + for (String bn : annotationsToFind) if (typeMatches(bn, node, typeRef)) { result.add(annotation); break; } @@ -1024,11 +1047,54 @@ public class EclipseHandlerUtil { return res; } - + + private static final char[] OBJECT_SIG = "Ljava/lang/Object;".toCharArray(); + + private static int compare(char[] a, char[] b) { + if (a == null) return b == null ? 0 : -1; + if (b == null) return +1; + int len = Math.min(a.length, b.length); + for (int i = 0; i < len; i++) { + if (a[i] < b[i]) return -1; + if (a[i] > b[i]) return +1; + } + return a.length < b.length ? -1 : a.length > b.length ? +1 : 0; + } + public static TypeReference makeType(TypeBinding binding, ASTNode pos, boolean allowCompound) { - if (binding.getClass() == EclipseReflectiveMembers.INTERSECTION_BINDING) { - Object[] arr = (Object[]) EclipseReflectiveMembers.reflect(EclipseReflectiveMembers.INTERSECTION_BINDING_TYPES, binding); - binding = (TypeBinding) arr[0]; + Object[] arr = null; + if (binding.getClass() == EclipseReflectiveMembers.INTERSECTION_BINDING1) { + arr = (Object[]) EclipseReflectiveMembers.reflect(EclipseReflectiveMembers.INTERSECTION_BINDING_TYPES1, binding); + } else if (binding.getClass() == EclipseReflectiveMembers.INTERSECTION_BINDING2) { + arr = (Object[]) EclipseReflectiveMembers.reflect(EclipseReflectiveMembers.INTERSECTION_BINDING_TYPES2, binding); + } + + if (arr != null) { + // Is there a class? Alphabetically lowest wins. + TypeBinding winner = null; + int winLevel = 0; // 100 = array, 50 = class, 20 = typevar, 15 = wildcard, 10 = interface, 1 = Object. + for (Object b : arr) { + if (b instanceof TypeBinding) { + TypeBinding tb = (TypeBinding) b; + int level = 0; + if (tb.isArrayType()) level = 100; + else if (tb.isClass()) level = 50; + else if (tb.isTypeVariable()) level = 20; + else if (tb.isWildcard()) level = 15; + else level = 10; + + if (level == 50 && compare(tb.signature(), OBJECT_SIG) == 0) level = 1; + + if (winLevel > level) continue; + if (winLevel < level) { + winner = tb; + winLevel = level; + continue; + } + if (compare(winner.signature(), tb.signature()) > 0) winner = tb; + } + } + binding = winner; } int dims = binding.dimensions(); binding = binding.leafComponentType(); @@ -1941,7 +2007,11 @@ public class EclipseHandlerUtil { private static final char[][] EDU_UMD_CS_FINDBUGS_ANNOTATIONS_SUPPRESSFBWARNINGS = Eclipse.fromQualifiedName("edu.umd.cs.findbugs.annotations.SuppressFBWarnings"); public static Annotation[] addSuppressWarningsAll(EclipseNode node, ASTNode source, Annotation[] originalAnnotationArray) { - Annotation[] anns = addAnnotation(source, originalAnnotationArray, TypeConstants.JAVA_LANG_SUPPRESSWARNINGS, new StringLiteral(ALL, 0, 0, 0)); + Annotation[] anns = originalAnnotationArray; + + if (!Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_SUPPRESSWARNINGS_ANNOTATIONS))) { + anns = addAnnotation(source, anns, TypeConstants.JAVA_LANG_SUPPRESSWARNINGS, new StringLiteral(ALL, 0, 0, 0)); + } if (Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_FINDBUGS_SUPPRESSWARNINGS_ANNOTATIONS))) { MemberValuePair mvp = new MemberValuePair(JUSTIFICATION, 0, 0, new StringLiteral(GENERATED_CODE, 0, 0, 0)); @@ -2418,6 +2488,26 @@ public class EclipseHandlerUtil { return array == null ? null : array.clone(); } + public static T[] concat(T[] first, T[] second, Class type) { + if (first == null) + return second; + if (second == null) + return first; + if (first.length == 0) + return second; + if (second.length == 0) + return first; + T[] result = newArray(type, first.length + second.length); + System.arraycopy(first, 0, result, 0, first.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + @SuppressWarnings("unchecked") + private static T[] newArray(Class type, int length) { + return (T[]) Array.newInstance(type, length); + } + public static boolean isDirectDescendantOfObject(EclipseNode typeNode) { if (!(typeNode.get() instanceof TypeDeclaration)) throw new IllegalArgumentException("not a type node"); TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get(); diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index b8e88522..801fe7e7 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.Receiver; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; @@ -485,7 +486,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { List> fieldNodes = new ArrayList>(); for (BuilderFieldData bfd : builderFields) { for (EclipseNode f : bfd.createdFields) { - fieldNodes.add(new Included(f, null, true)); + fieldNodes.add(new Included(f, null, true, false)); } } MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD); @@ -683,7 +684,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { return decl; } - static Argument[] generateBuildArgs(CheckerFrameworkVersion cfv, EclipseNode type, List builderFields, ASTNode source) { + static Receiver generateBuildReceiver(CheckerFrameworkVersion cfv, EclipseNode type, List builderFields, ASTNode source) { if (!cfv.generateCalledMethods()) return null; List mandatories = new ArrayList(); @@ -706,9 +707,11 @@ public class HandleBuilder extends EclipseAnnotationHandler { } ann.memberValue = arr; } - Argument arg = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, generateTypeReference(type, source.sourceStart), Modifier.FINAL); - arg.annotations = new Annotation[] {ann}; - return new Argument[] {arg}; + + QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(type, source.sourceStart); + typeReference.annotations = new Annotation[typeReference.tokens.length][]; + typeReference.annotations[0] = new Annotation[] {ann}; + return new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); } public MethodDeclaration generateBuildMethod(CheckerFrameworkVersion cfv, EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source, AccessLevel access) { @@ -802,7 +805,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { if (cfv.generateSideEffectFree()) { out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; } - out.arguments = generateBuildArgs(cfv, type, builderFields, source); + out.receiver = generateBuildReceiver(cfv, type, builderFields, source); if (staticName == null) createRelevantNonNullAnnotation(type, out); out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; @@ -953,16 +956,14 @@ public class HandleBuilder extends EclipseAnnotationHandler { MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, chain, toEclipseModifier(access), sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(source, annotations)) : Collections.emptyList()); if (cfv.generateCalledMethods()) { - Argument[] arr = setter.arguments == null ? new Argument[0] : setter.arguments; - Argument[] newArr = new Argument[arr.length + 1]; - System.arraycopy(arr, 0, newArr, 1, arr.length); - newArr[0] = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, generateTypeReference(builderType, 0), Modifier.FINAL); char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED); - SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss( - source, nameNotCalled.length)), source.sourceStart); + SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart); ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0); - newArr[0].annotations = new Annotation[] {ann}; - setter.arguments = newArr; + + QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(builderType, 0); + typeReference.annotations = new Annotation[typeReference.tokens.length][]; + typeReference.annotations[0] = new Annotation[] {ann}; + setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); } injectMethod(builderType, setter); } diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 129fa7c0..06c9ecd9 100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -84,13 +84,14 @@ import org.mangosdk.spi.ProviderFor; public class HandleConstructor { @ProviderFor(EclipseAnnotationHandler.class) public static class HandleNoArgsConstructor extends EclipseAnnotationHandler { + private static final String NAME = NoArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.NO_ARGS_CONSTRUCTOR_FLAG_USAGE, "@NoArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor"); EclipseNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, NoArgsConstructor.class.getSimpleName())) return; + if (!checkLegality(typeNode, annotationNode, NAME)) return; NoArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); String staticName = ann.staticName(); @@ -106,13 +107,14 @@ public class HandleConstructor { @ProviderFor(EclipseAnnotationHandler.class) public static class HandleRequiredArgsConstructor extends EclipseAnnotationHandler { + private static final String NAME = RequiredArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.REQUIRED_ARGS_CONSTRUCTOR_FLAG_USAGE, "@RequiredArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor"); EclipseNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, RequiredArgsConstructor.class.getSimpleName())) return; + if (!checkLegality(typeNode, annotationNode, NAME)) return; RequiredArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); if (level == AccessLevel.NONE) return; @@ -166,13 +168,15 @@ public class HandleConstructor { @ProviderFor(EclipseAnnotationHandler.class) public static class HandleAllArgsConstructor extends EclipseAnnotationHandler { + private static final String NAME = AllArgsConstructor.class.getSimpleName(); + private HandleConstructor handleConstructor = new HandleConstructor(); @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.ALL_ARGS_CONSTRUCTOR_FLAG_USAGE, "@AllArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor"); EclipseNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, AllArgsConstructor.class.getSimpleName())) return; + if (!checkLegality(typeNode, annotationNode, NAME)) return; AllArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); if (level == AccessLevel.NONE) return; diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index 2db7591c..cee3912c 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -136,9 +136,8 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler { } if (addSuppressWarningsUnchecked) { + List suppressions = new ArrayList(2); + if (!Boolean.FALSE.equals(fieldNode.getAst().readConfiguration(ConfigurationKeys.ADD_SUPPRESSWARNINGS_ANNOTATIONS))) { + suppressions.add(new StringLiteral(ALL, 0, 0, 0)); + } + suppressions.add(new StringLiteral(UNCHECKED, 0, 0, 0)); ArrayInitializer arr = new ArrayInitializer(); - arr.expressions = new Expression[2]; - arr.expressions[0] = new StringLiteral(ALL, 0, 0, 0); - arr.expressions[1] = new StringLiteral(UNCHECKED, 0, 0, 0); + arr.expressions = suppressions.toArray(new Expression[0]); method.annotations = addAnnotation(source, method.annotations, TypeConstants.JAVA_LANG_SUPPRESSWARNINGS, arr); } diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index 7a140193..a0e431e5 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -51,6 +51,7 @@ import lombok.core.configuration.LogDeclaration.LogFactoryParameter; import lombok.core.handlers.LoggingFramework; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; public class HandleLog { private static final IdentifierName LOG = IdentifierName.valueOf("log"); @@ -59,7 +60,7 @@ public class HandleLog { throw new UnsupportedOperationException(); } - public static void processAnnotation(LoggingFramework framework, AnnotationValues annotation, Annotation source, EclipseNode annotationNode, String loggerTopic) { + public static void processAnnotation(LoggingFramework framework, AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { EclipseNode owner = annotationNode.up(); switch (owner.getKind()) { @@ -84,15 +85,18 @@ public class HandleLog { annotationNode.addWarning("Field '" + logFieldName + "' already exists."); return; } - - if (loggerTopic != null && loggerTopic.trim().isEmpty()) loggerTopic = null; + + Object valueGuess = annotation.getValueGuess("topic"); + Expression loggerTopic = (Expression) annotation.getActualExpression("topic"); + + if (valueGuess instanceof String && ((String) valueGuess).trim().isEmpty()) loggerTopic = null; if (framework.getDeclaration().getParametersWithTopic() == null && loggerTopic != null) { annotationNode.addError(framework.getAnnotationAsString() + " does not allow a topic."); loggerTopic = null; } if (framework.getDeclaration().getParametersWithoutTopic() == null && loggerTopic == null) { annotationNode.addError(framework.getAnnotationAsString() + " requires a topic."); - loggerTopic = ""; + loggerTopic = new StringLiteral(new char[]{}, 0, 0, 0); } ClassLiteralAccess loggingType = selfType(owner, source); @@ -122,7 +126,7 @@ public class HandleLog { return result; } - private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType, String logFieldName, boolean useStatic, String loggerTopic) { + private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType, String logFieldName, boolean useStatic, Expression loggerTopic) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; @@ -165,7 +169,7 @@ public class HandleLog { return typeReference; } - private static final Expression[] createFactoryParameters(ClassLiteralAccess loggingType, Annotation source, List parameters, String loggerTopic) { + private static final Expression[] createFactoryParameters(ClassLiteralAccess loggingType, Annotation source, List parameters, Expression loggerTopic) { Expression[] expressions = new Expression[parameters.size()]; int pS = source.sourceStart, pE = source.sourceEnd; @@ -192,7 +196,7 @@ public class HandleLog { expressions[i] = factoryParameterCall; break; case TOPIC: - expressions[i] = new StringLiteral(loggerTopic.toCharArray(), pS, pE, 0); + expressions[i] = EclipseHandlerUtil.copyAnnotationMemberValue(loggerTopic); break; case NULL: expressions[i] = new NullLiteral(pS, pE); @@ -219,7 +223,7 @@ public class HandleLog { public static class HandleCommonsLog extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_COMMONS_FLAG_USAGE, "@apachecommons.CommonsLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode); } } @@ -230,7 +234,7 @@ public class HandleLog { public static class HandleJulLog extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JUL_FLAG_USAGE, "@java.Log", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode); } } @@ -241,7 +245,7 @@ public class HandleLog { public static class HandleLog4jLog extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J_FLAG_USAGE, "@Log4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode); } } @@ -252,7 +256,7 @@ public class HandleLog { public static class HandleLog4j2Log extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J2_FLAG_USAGE, "@Log4j2", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.LOG4J2, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.LOG4J2, annotation, source, annotationNode); } } @@ -263,7 +267,7 @@ public class HandleLog { public static class HandleSlf4jLog extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_SLF4J_FLAG_USAGE, "@Slf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode); } } @@ -274,7 +278,7 @@ public class HandleLog { public static class HandleXSlf4jLog extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_XSLF4J_FLAG_USAGE, "@XSlf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.XSLF4J, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.XSLF4J, annotation, source, annotationNode); } } @@ -285,7 +289,7 @@ public class HandleLog { public static class HandleJBossLog extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JBOSSLOG_FLAG_USAGE, "@JBossLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.JBOSSLOG, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.JBOSSLOG, annotation, source, annotationNode); } } @@ -296,7 +300,7 @@ public class HandleLog { public static class HandleFloggerLog extends EclipseAnnotationHandler { @Override public void handle(AnnotationValues 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, ""); + processAnnotation(LoggingFramework.FLOGGER, annotation, source, annotationNode); } } @@ -313,7 +317,7 @@ public class HandleLog { return; } LoggingFramework framework = new LoggingFramework(lombok.CustomLog.class, logDeclaration); - processAnnotation(framework, annotation, source, annotationNode, annotation.getInstance().topic()); + processAnnotation(framework, annotation, source, annotationNode); } } } diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java index c4d42c2e..903d098b 100644 --- a/src/core/lombok/eclipse/handlers/HandleNonNull.java +++ b/src/core/lombok/eclipse/handlers/HandleNonNull.java @@ -40,7 +40,6 @@ import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; -import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; @@ -232,11 +231,11 @@ public class HandleNonNull extends EclipseAnnotationHandler { Expression cond = isIf ? ((IfStatement) stat).condition : ((AssertStatement) stat).assertExpression; if (!(cond instanceof EqualExpression)) return null; EqualExpression bin = (EqualExpression) cond; - int operatorId = ((bin.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT); + String op = bin.operatorToString(); if (isIf) { - if (operatorId != OperatorIds.EQUAL_EQUAL) return null; + if (!"==".equals(op)) return null; } else { - if (operatorId != OperatorIds.NOT_EQUAL) return null; + if (!"!=".equals(op)) return null; } if (!(bin.left instanceof SingleNameReference)) return null; if (!(bin.right instanceof NullLiteral)) return null; diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 6634d1c8..b1e7c419 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.Receiver; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; @@ -144,9 +145,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { generateBuilderMethod = true; } if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; - + boolean toBuilder = superbuilderAnnotation.toBuilder(); - + EclipseNode tdParent = annotationNode.up(); java.util.List builderFields = new ArrayList(); @@ -233,7 +234,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { TypeReference extendsClause = td.superclass; TypeReference superclassBuilderClass = null; TypeReference[] typeArguments = new TypeReference[] { - new SingleTypeReference(classGenericName.toCharArray(), 0), + new SingleTypeReference(classGenericName.toCharArray(), 0), new SingleTypeReference(builderGenericName.toCharArray(), 0) }; if (extendsClause instanceof QualifiedTypeReference) { @@ -242,7 +243,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName); char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); - tokens[tokens.length] = superclassBuilderClassName.toCharArray(); + tokens[tokens.length-1] = superclassBuilderClassName.toCharArray(); long[] poss = new long[tokens.length]; Arrays.fill(poss, p); @@ -274,8 +275,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // If there is no superclass, superclassBuilderClassExpression is still == null at this point. // You can use it to check whether to inherit or not. - generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, - superclassBuilderClass != null); + if (!constructorExists(tdParent, builderClassName)) { + generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, + superclassBuilderClass != null); + } // Create the abstract builder class, or reuse an existing one. EclipseNode builderType = findInnerClass(tdParent, builderClassName); @@ -330,14 +333,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); injectFieldAndMarkGenerated(builderType, cleanDecl); } - + if (toBuilder) { // Generate $fillValuesFrom() method in the abstract builder. injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClass != null, builderGenericName, classGenericName, builderClassName, typeParams)); // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class. injectMethod(builderType, generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields, ast, superbuilderAnnotation.setterPrefix())); } - + // Generate abstract self() and build() methods in the abstract builder. injectMethod(builderType, generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClass != null, builderGenericName)); injectMethod(builderType, generateAbstractBuildMethod(cfv, builderType, buildMethodName, builderFields, superclassBuilderClass != null, classGenericName, ast)); @@ -352,7 +355,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { List> fieldNodes = new ArrayList>(); for (BuilderFieldData bfd : builderFields) { for (EclipseNode f : bfd.createdFields) { - fieldNodes.add(new Included(f, null, true)); + fieldNodes.add(new Included(f, null, true, false)); } } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. @@ -383,22 +386,23 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderImplType, annotationNode); } - + if (toBuilder) { // Add the toBuilder() method to the annotated class. switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, tdParent, 0)) { case EXISTS_BY_USER: - annotationNode.addWarning("Not generating toBuilder() as it already exists."); break; case NOT_EXISTS: injectMethod(tdParent, generateToBuilderMethod(cfv, builderClassName, builderImplClassName, tdParent, typeParams, ast)); + break; default: // Should not happen. } } - + // Create the self() and build() methods in the BuilderImpl. injectMethod(builderImplType, generateSelfMethod(cfv, builderImplType, typeParams, p)); + if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { injectMethod(builderImplType, generateBuildMethod(cfv, builderImplType, buildMethodName, returnType, builderFields, ast)); } @@ -416,7 +420,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } } } - + private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass, TypeReference superclassBuilderClass, TypeParameter[] typeParams, ASTNode source, String classGenericName, String builderGenericName) { @@ -445,7 +449,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { builder.superclass = copyType(superclassBuilderClass, source); builder.createDefaultConstructor(false, true); - + builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); } @@ -803,8 +807,8 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccProtected; Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get()); - Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER): null; - Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__PURE): null; + Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null; + Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__PURE) : null; if (rrAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn, sefAnn}; else if (rrAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn}; else if (sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; @@ -829,7 +833,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { if (overrideAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; else if (overrideAnn != null) out.annotations = new Annotation[] {overrideAnn}; else if (sefAnn != null) out.annotations = new Annotation[] {sefAnn}; - out.arguments = HandleBuilder.generateBuildArgs(cfv, builderType, builderFields, source); + out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source); out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } @@ -854,7 +858,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)}; statements.add(new ReturnStatement(allocationStatement, 0, 0)); out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); - out.arguments = HandleBuilder.generateBuildArgs(cfv, builderType, builderFields, source); + out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source); createRelevantNonNullAnnotation(builderType, out); out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; @@ -968,15 +972,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic, sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(source, annosOnParam)) : Collections.emptyList()); if (cfv.generateCalledMethods()) { - Argument[] arr = setter.arguments == null ? new Argument[0] : setter.arguments; - Argument[] newArr = new Argument[arr.length + 1]; - System.arraycopy(arr, 0, newArr, 1, arr.length); - newArr[0] = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, generateTypeReference(builderType, 0), Modifier.FINAL); char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED); SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart); ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0); - newArr[0].annotations = new Annotation[] {ann}; - setter.arguments = newArr; + + QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(builderType, 0); + typeReference.annotations = new Annotation[typeReference.tokens.length][]; + typeReference.annotations[0] = new Annotation[] {ann}; + setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); } injectMethod(builderType, setter); } @@ -1159,4 +1162,26 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { System.arraycopy(name, 0, out, prefix.length, name.length); return out; } + + private boolean constructorExists(EclipseNode type, String builderClassName) { + if (type != null && type.get() instanceof TypeDeclaration) { + TypeDeclaration typeDecl = (TypeDeclaration)type.get(); + if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) { + if (def instanceof ConstructorDeclaration) { + if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue; + if (!def.isConstructor()) continue; + if (isTolerate(type, def)) continue; + if (def.arguments.length != 1) continue; + + // Cannot use typeMatches() here, because the parameter could be fully-qualified, partially-qualified, or not qualified. + // A string-compare of the last part should work. If it's a false-positive, users could still @Tolerate it. + char[] typeName = def.arguments[0].type.getLastToken(); + if (builderClassName.equals(String.valueOf(typeName))) + return true; + } + } + } + + return false; + } } diff --git a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java index ada09d0e..2349f839 100644 --- a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java +++ b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java @@ -113,7 +113,7 @@ public class HandleUtilityClass extends EclipseAnnotationHandler { if (typeNode.up().getKind() == Kind.COMPILATION_UNIT) markStatic = false; if (markStatic && typeNode.up().getKind() == Kind.TYPE) { TypeDeclaration typeDecl = (TypeDeclaration) typeNode.up().get(); - if ((typeDecl.modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0) markStatic = false; + if ((typeDecl.modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0) markStatic = false; } if (markStatic) classDecl.modifiers |= ClassFileConstants.AccStatic; diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 392418ff..395d2e59 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -175,8 +175,10 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { md.returnType = returnType; char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray(); - md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); - + Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); + md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); + if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); HandleNonNull.INSTANCE.fix(injectMethod(builderType, md)); @@ -213,8 +215,10 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { md.returnType = returnType; char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray(); - md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); - + Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); + md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); + if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); injectMethod(builderType, md); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index 375f4e2c..deab4530 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -153,8 +153,10 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula md.returnType = returnType; char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray(); - md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); - + Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); + md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); + if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); HandleNonNull.INSTANCE.fix(injectMethod(builderType, md)); @@ -189,8 +191,10 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula md.returnType = returnType; char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray(); - md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); - + Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); + md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); + if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); injectMethod(builderType, md); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index cb7d9ed6..1a40369d 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -252,7 +252,9 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer String setterName = HandlerUtil.buildAccessorName(setterPrefix, name); md.selector = setterName.toCharArray(); - md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); + md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); @@ -326,7 +328,9 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer String setterName = HandlerUtil.buildAccessorName(setterPrefix, name); md.selector = setterName.toCharArray(); - md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); + Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); + md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); diff --git a/src/core/lombok/experimental/WithBy.java b/src/core/lombok/experimental/WithBy.java index 10155b91..6b16a5e6 100644 --- a/src/core/lombok/experimental/WithBy.java +++ b/src/core/lombok/experimental/WithBy.java @@ -76,7 +76,7 @@ import lombok.AccessLevel; * but with {@code @WithBy}, you'd write: * *
- *     movie = movie.withDirectorBy(d -> d.withBirthDateBy(bd -> bd.plusDays(1)));
+ *     movie = movie.withDirectorBy(d -> d.withBirthDateBy(bd -> bd.plusDays(1)));
  * 
*/ @Target({ElementType.FIELD, ElementType.TYPE}) diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index f6cd5571..86ff7646 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -79,6 +79,8 @@ public class JavacAST extends AST { private final Log log; private final ErrorLog errorLogger; private final Context context; + private static final URI NOT_CALCULATED_MARKER = URI.create("https://projectlombok.org/not/calculated"); + private URI memoizedAbsoluteFileLocation = NOT_CALCULATED_MARKER; /** * Creates a new JavacAST of the provided Compilation Unit. @@ -102,7 +104,10 @@ public class JavacAST extends AST { } @Override public URI getAbsoluteFileLocation() { - return getAbsoluteFileLocation((JCCompilationUnit) top().get()); + if (memoizedAbsoluteFileLocation == NOT_CALCULATED_MARKER) { + memoizedAbsoluteFileLocation = getAbsoluteFileLocation((JCCompilationUnit) top().get()); + } + return memoizedAbsoluteFileLocation; } public static URI getAbsoluteFileLocation(JCCompilationUnit cu) { @@ -258,7 +263,7 @@ public class JavacAST extends AST { if (typeUse == null) return null; - if (typeUse.getClass().getSimpleName().equals("JCAnnotatedType")) { + if (typeUse.getClass().getName().equals("com.sun.tools.javac.tree.JCTree$JCAnnotatedType")) { initJcAnnotatedType(typeUse.getClass()); Collection anns = Permit.permissiveReadField(Collection.class, JCANNOTATEDTYPE_ANNOTATIONS, typeUse); JCExpression underlying = Permit.permissiveReadField(JCExpression.class, JCANNOTATEDTYPE_UNDERLYINGTYPE, typeUse); @@ -381,7 +386,7 @@ public class JavacAST extends AST { if (statement instanceof JCClassDecl) return buildType((JCClassDecl) statement); if (statement instanceof JCVariableDecl) return buildLocalVar((JCVariableDecl) statement, Kind.LOCAL); if (statement instanceof JCTry) return buildTry((JCTry) statement); - if (statement.getClass().getSimpleName().equals("JCLambda")) return buildLambda(statement); + if (statement.getClass().getName().equals("com.sun.tools.javac.tree.JCTree$JCLambda")) return buildLambda(statement); if (setAndGetAsHandled(statement)) return null; return drill(statement); diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index 19bbeae3..3de3f38b 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -27,10 +27,6 @@ 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; @@ -43,8 +39,12 @@ 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; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.Name; + +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.javac.handlers.JavacHandlerUtil; /** * Javac specific version of the LombokNode class. @@ -345,6 +345,29 @@ public class JavacNode extends lombok.core.LombokNode concat(final Type t, final Collection ts) { + if (t == null) return ts; + + return new Iterable() { + @Override public Iterator iterator() { + return new Iterator() { + private boolean first = true; + private Iterator wrap = ts == null ? null : ts.iterator(); + @Override public boolean hasNext() { + if (first) return true; + if (wrap == null) return false; + return wrap.hasNext(); + } + + @Override public Type next() { + if (first) { + first = false; + return t; + } + if (wrap == null) throw new NoSuchElementException(); + return wrap.next(); + } + + @Override public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + private static int compare(Name a, Name b) { + return a.compareTo(b); + } + private static JCExpression typeToJCTree0(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid, boolean allowCapture) throws TypeNotConvertibleException { // NB: There's such a thing as maker.Type(type), but this doesn't work very well; it screws up anonymous classes, captures, and adds an extra prefix dot for some reason too. // -- so we write our own take on that here. @@ -335,12 +375,30 @@ public class JavacResolution { if (symbol.name.length() == 0) { // Anonymous inner class if (type instanceof ClassType) { - List ifaces = ((ClassType) type).interfaces_field; + Type winner = null; + int winLevel = 0; // 100 = array, 50 = class, 20 = typevar, 15 = wildcard, 10 = interface, 1 = Object. Type supertype = ((ClassType) type).supertype_field; - if (isObject(supertype) && ifaces != null && ifaces.length() > 0) { - return typeToJCTree(ifaces.get(0), ast, allowCompound, allowVoid, allowCapture); + List ifaces = ((ClassType) type).interfaces_field; + for (Type t : concat(supertype, ifaces)) { + int level = 0; + if (t instanceof ArrayType) level = 100; + else if (t instanceof TypeVar) level = 20; + else if (t instanceof WildcardType) level = 15; + else if (t.isInterface()) level = 10; + else if (isObject(t)) level = 1; + else if (t instanceof ClassType) level = 50; + else level = 5; + + if (winLevel > level) continue; + if (winLevel < level) { + winner = t; + winLevel = level; + continue; + } + if (compare(winner.tsym.getQualifiedName(), t.tsym.getQualifiedName()) < 0) winner = t; } - if (supertype != null) return typeToJCTree(supertype, ast, allowCompound, allowVoid, allowCapture); + if (winner == null) return createJavaLangObject(ast); + return typeToJCTree(winner, ast, allowCompound, allowVoid, allowCapture); } throw new TypeNotConvertibleException("Anonymous inner class"); } diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java index 625fb283..a2e00680 100644 --- a/src/core/lombok/javac/JavacTransformer.java +++ b/src/core/lombok/javac/JavacTransformer.java @@ -21,7 +21,7 @@ */ package lombok.javac; -import java.util.ArrayList; +import java.util.List; import java.util.SortedSet; import javax.annotation.processing.Messager; @@ -34,7 +34,6 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; import lombok.ConfigurationKeys; import lombok.core.CleanupRegistry; @@ -57,31 +56,15 @@ public class JavacTransformer { return handlers.getPrioritiesRequiringResolutionReset(); } - public void transform(long priority, Context context, java.util.List compilationUnitsRaw, CleanupRegistry cleanup) { - List compilationUnits; - if (compilationUnitsRaw instanceof List) { - compilationUnits = (List) compilationUnitsRaw; - } else { - compilationUnits = List.nil(); - for (int i = compilationUnitsRaw.size() -1; i >= 0; i--) { - compilationUnits = compilationUnits.prepend(compilationUnitsRaw.get(i)); - } - } - - java.util.List asts = new ArrayList(); - + public void transform(long priority, Context context, List compilationUnits, CleanupRegistry cleanup) { for (JCCompilationUnit unit : compilationUnits) { if (!Boolean.TRUE.equals(LombokConfiguration.read(ConfigurationKeys.LOMBOK_DISABLE, JavacAST.getAbsoluteFileLocation(unit)))) { - asts.add(new JavacAST(messager, context, unit, cleanup)); + JavacAST ast = new JavacAST(messager, context, unit, cleanup); + ast.traverse(new AnnotationVisitor(priority)); + handlers.callASTVisitors(ast, priority); + if (ast.isChanged()) LombokOptions.markChanged(context, (JCCompilationUnit) ast.top().get()); } } - - for (JavacAST ast : asts) { - ast.traverse(new AnnotationVisitor(priority)); - handlers.callASTVisitors(ast, priority); - } - - for (JavacAST ast : asts) if (ast.isChanged()) LombokOptions.markChanged(context, (JCCompilationUnit) ast.top().get()); } private class AnnotationVisitor extends JavacASTAdapter { diff --git a/src/core/lombok/javac/apt/LombokFileObjects.java b/src/core/lombok/javac/apt/LombokFileObjects.java index f6643db3..880ef1fd 100644 --- a/src/core/lombok/javac/apt/LombokFileObjects.java +++ b/src/core/lombok/javac/apt/LombokFileObjects.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2019 The Project Lombok Authors. + * Copyright (C) 2010-2020 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,23 +22,15 @@ package lombok.javac.apt; -import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.URI; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; -import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import javax.tools.FileObject; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; - -import com.sun.tools.javac.file.BaseFileManager; import lombok.core.DiagnosticsReceiver; import lombok.permit.Permit; @@ -116,22 +108,20 @@ final class LombokFileObjects { if (jfmClassName.equals("com.sun.tools.javac.file.JavacFileManager")) { try { Class superType = Class.forName("com.sun.tools.javac.file.BaseFileManager"); - if (superType.isInstance(jfm)) { - return new Java9Compiler(jfm); - } + if (superType.isInstance(jfm)) return java9Compiler(jfm); } catch (Throwable e) {} return Compiler.JAVAC7; } if (KNOWN_JAVA9_FILE_MANAGERS.contains(jfmClassName)) { try { - return new Java9Compiler(jfm); + return java9Compiler(jfm); } catch (Throwable e) {} } try { if (Class.forName("com.sun.tools.javac.file.PathFileObject") == null) throw new NullPointerException(); - return new Java9Compiler(jfm); + return java9Compiler(jfm); } catch (Throwable e) {} try { if (Class.forName("com.sun.tools.javac.file.BaseFileObject") == null) throw new NullPointerException(); @@ -156,122 +146,24 @@ final class LombokFileObjects { return compiler.wrap(new InterceptingJavaFileObject(delegate, fileName, diagnostics, compiler.getDecoderMethod())); } - static class Java9Compiler implements Compiler { - private final BaseFileManager fileManager; - - public Java9Compiler(JavaFileManager jfm) { - fileManager = asBaseFileManager(jfm); - } - - @Override public JavaFileObject wrap(LombokFileObject fileObject) { - Path p; try { - p = toPath(fileObject); - } catch (Exception e) { - p = null; - } - - // J9BFOW extends javac's internal file base impl of javax.tools.JavaFileObject. - // J9JFOW just straight implements it. Probably J9JFOW is fine, but we decided to extend java's internal impl possibly for a reason. - // Some exotic build environments don't _have_ file objects and crash with FileNotFoundEx, so if that happens, let's try the alternative. - if (p != null) return new Javac9BaseFileObjectWrapper(fileManager, p, fileObject); - return new Javac9JavaFileObjectWrapper(fileObject); - } - - @Override public Method getDecoderMethod() { + private static Constructor j9CompilerConstructor = null; + private static Compiler java9Compiler(JavaFileManager jfm) { + try { + if (j9CompilerConstructor == null) j9CompilerConstructor = Class.forName("lombok.javac.apt.Java9Compiler").getConstructor(JavaFileManager.class); + return (Compiler) j9CompilerConstructor.newInstance(jfm); + } catch (ClassNotFoundException e) { return null; - } - - private static Path toPath(LombokFileObject fileObject) { - URI uri = fileObject.toUri(); - if (uri.getScheme() == null) { - uri = URI.create("file:///" + uri); - } - try { - return Paths.get(uri); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Problems in URI '" + uri + "' (" + fileObject.toUri() + ")", e); - } - } - - private static BaseFileManager asBaseFileManager(JavaFileManager jfm) { - if (jfm instanceof BaseFileManager) { - return (BaseFileManager) jfm; - } - return new FileManagerWrapper(jfm); - } - - static class FileManagerWrapper extends BaseFileManager { - JavaFileManager manager; - - public FileManagerWrapper(JavaFileManager manager) { - super(null); - this.manager = manager; - } - - @Override - public int isSupportedOption(String option) { - return manager.isSupportedOption(option); - } - - @Override - public ClassLoader getClassLoader(Location location) { - return manager.getClassLoader(location); - } - - @Override - public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { - return manager.list(location, packageName, kinds, recurse); - } - - @Override - public String inferBinaryName(Location location, JavaFileObject file) { - return manager.inferBinaryName(location, file); - } - - @Override - public boolean isSameFile(FileObject a, FileObject b) { - return manager.isSameFile(a, b); - } - - @Override - public boolean handleOption(String current, Iterator remaining) { - return manager.handleOption(current, remaining); - } - - @Override - public boolean hasLocation(Location location) { - return manager.hasLocation(location); - } - - @Override - public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { - return manager.getJavaFileForInput(location, className, kind); - } - - @Override - public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { - return manager.getJavaFileForOutput(location, className, kind, sibling); - } - - @Override - public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { - return manager.getFileForInput(location, packageName, relativeName); - } - - @Override - public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { - return manager.getFileForOutput(location, packageName, relativeName, sibling); - } - - @Override - public void flush() throws IOException { - manager.flush(); - } - - @Override - public void close() throws IOException { - manager.close(); - } + } catch (NoSuchMethodException e) { + return null; + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof RuntimeException) throw (RuntimeException) t; + if (t instanceof Error) throw (Error) t; + throw new RuntimeException(t); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); } } } diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index c32e09d5..852e5de6 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -24,6 +24,7 @@ package lombok.javac.apt; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; @@ -42,7 +43,6 @@ import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; -import javax.lang.model.element.QualifiedNameable; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileManager; @@ -371,7 +371,7 @@ public class LombokProcessor extends AbstractProcessor { private String getModuleNameFor(Element element) { while (element != null) { - if (element.getKind().name().equals("MODULE")) return ModuleNameOracle.getModuleName(element); + if (element.getKind().name().equals("MODULE")) return getModuleName(element); Element n = element.getEnclosingElement(); if (n == element) return null; element = n; @@ -379,12 +379,24 @@ public class LombokProcessor extends AbstractProcessor { return null; } - // QualifiedNameable is a java7 thing, so to remain compatible with java6, shove this into an inner class to avoid the ClassNotFoundError. - private static class ModuleNameOracle { - static String getModuleName(Element element) { - if (!(element instanceof QualifiedNameable)) return null; - String name = ((QualifiedNameable) element).getQualifiedName().toString().trim(); + private static Class qualifiedNamableClass = null; + private static Method qualifiedNamableQualifiedNameMethod = null; + // QualifiedNameable isn't in java 6, so to remain compatible with java6, use reflection. + private static String getModuleName(Element element) { + try { + if (qualifiedNamableClass == null) qualifiedNamableClass = Class.forName("javax.lang.model.element.QualifiedNamable"); + if (!qualifiedNamableClass.isInstance(element)) return null; + if (qualifiedNamableQualifiedNameMethod == null) qualifiedNamableQualifiedNameMethod = qualifiedNamableClass.getMethod("getQualifiedName"); + String name = qualifiedNamableQualifiedNameMethod.invoke(element).toString().trim(); return name.isEmpty() ? null : name; + } catch (ClassNotFoundException e) { + return null; + } catch (NoSuchMethodException e) { + return null; + } catch (InvocationTargetException e) { + return null; + } catch (IllegalAccessException e) { + return null; } } diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 91a74d62..7e87ce11 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -27,6 +27,8 @@ import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.lang.model.element.Modifier; @@ -38,6 +40,7 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; 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.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; @@ -432,7 +435,7 @@ public class HandleBuilder extends JavacAnnotationHandler { java.util.List> fieldNodes = new ArrayList>(); for (BuilderFieldData bfd : builderFields) { for (JavacNode f : bfd.createdFields) { - fieldNodes.add(new Included(f, null, true)); + fieldNodes.add(new Included(f, null, true, false)); } } @@ -845,11 +848,30 @@ public class HandleBuilder extends JavacAnnotationHandler { newMethod.params = List.of(recv, newMethod.params.get(0)); } recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext()); - copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER, true); + if (source.up().getKind() == Kind.METHOD) { + copyJavadocFromParam(originalFieldNode.up(), newMethod, paramName.toString()); + } else { + copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER, true); + } injectMethod(builderType, newMethod); } + private void copyJavadocFromParam(JavacNode from, JCMethodDecl to, String param) { + try { + JCCompilationUnit cu = ((JCCompilationUnit) from.top().get()); + String methodComment = Javac.getDocComment(cu, from.get()); + if (methodComment == null) return; + + Pattern pattern = Pattern.compile("@param " + param + " (\\S|\\s)+?(?=^ ?@)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(methodComment); + if (matcher.find()) { + String newJavadoc = addReturnsThisIfNeeded(matcher.group()); + Javac.setDocComment(cu, to, newJavadoc); + } + } catch (Exception ignore) {} + } + public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List typeParams, JCAnnotation ast, AccessLevel access) { JavacTreeMaker maker = tdParent.getTreeMaker(); int modifiers = toJavacModifier(access); diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index e0abb53b..2a683767 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -68,6 +68,7 @@ import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; public class HandleConstructor { @ProviderFor(JavacAnnotationHandler.class) public static class HandleNoArgsConstructor extends JavacAnnotationHandler { + private static final String NAME = NoArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { @@ -76,7 +77,7 @@ public class HandleConstructor { deleteAnnotationIfNeccessary(annotationNode, NoArgsConstructor.class); deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, NoArgsConstructor.class.getSimpleName())) return; + if (!checkLegality(typeNode, annotationNode, NAME)) return; List onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor", annotationNode); NoArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); @@ -89,6 +90,7 @@ public class HandleConstructor { @ProviderFor(JavacAnnotationHandler.class) public static class HandleRequiredArgsConstructor extends JavacAnnotationHandler { + private static final String NAME = RequiredArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { @@ -97,7 +99,7 @@ public class HandleConstructor { deleteAnnotationIfNeccessary(annotationNode, RequiredArgsConstructor.class); deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, RequiredArgsConstructor.class.getSimpleName())) return; + if (!checkLegality(typeNode, annotationNode, NAME)) return; List onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor", annotationNode); RequiredArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); @@ -138,6 +140,7 @@ public class HandleConstructor { @ProviderFor(JavacAnnotationHandler.class) public static class HandleAllArgsConstructor extends JavacAnnotationHandler { + private static final String NAME = AllArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { @@ -146,7 +149,7 @@ public class HandleConstructor { deleteAnnotationIfNeccessary(annotationNode, AllArgsConstructor.class); deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, AllArgsConstructor.class.getSimpleName())) return; + if (!checkLegality(typeNode, annotationNode, NAME)) return; List onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor", annotationNode); AllArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); diff --git a/src/core/lombok/javac/handlers/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java index 367b2cff..d6e76ab1 100644 --- a/src/core/lombok/javac/handlers/HandleDelegate.java +++ b/src/core/lombok/javac/handlers/HandleDelegate.java @@ -48,6 +48,7 @@ import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Attribute.Compound; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.ClassType; @@ -175,14 +176,14 @@ public class HandleDelegate extends JavacAnnotationHandler { List signaturesToExclude = new ArrayList(); Set banList = new HashSet(); banList.addAll(METHODS_IN_OBJECT); - /* To exclude all methods in the class itself, try this: - for (Symbol member : ((JCClassDecl)typeNode.get()).sym.getEnclosedElements()) { - if (member instanceof MethodSymbol) { - MethodSymbol method = (MethodSymbol) member; - banList.add(printSig((ExecutableType) method.asType(), method.name, annotationNode.getTypesUtil())); + + // Add already implemented methods to ban list + JavacNode typeNode = upToTypeNode(annotationNode); + for (Symbol m : ((JCClassDecl)typeNode.get()).sym.getEnclosedElements()) { + if (m instanceof MethodSymbol) { + banList.add(printSig((ExecutableType) m.asType(), m.name, annotationNode.getTypesUtil())); } } - */ try { for (Type t : toExclude) { @@ -389,10 +390,11 @@ public class HandleDelegate extends JavacAnnotationHandler { boolean isDeprecated = (member.flags() & DEPRECATED) != 0; signatures.add(new MethodSig(member.name, methodType, isDeprecated, exElem)); } - - if (ct.supertype_field instanceof ClassType) addMethodBindings(signatures, (ClassType) ct.supertype_field, types, banList); - if (ct.interfaces_field != null) for (Type iface : ct.interfaces_field) { - if (iface instanceof ClassType) addMethodBindings(signatures, (ClassType) iface, types, banList); + + for (Type type : types.directSupertypes(ct)) { + if (type instanceof ClassType) { + addMethodBindings(signatures, (ClassType) type, types, banList); + } } } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 985873c1..110941d6 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -232,9 +232,17 @@ public class HandleGetter extends JavacAnnotationHandler { List statements; JCTree toClearOfMarkers = null; + int[] methodArgPos = null; boolean addSuppressWarningsUnchecked = false; if (lazy && !inNetbeansEditor(field)) { toClearOfMarkers = fieldNode.init; + if (toClearOfMarkers instanceof JCMethodInvocation) { + List args = ((JCMethodInvocation) toClearOfMarkers).args; + methodArgPos = new int[args.length()]; + for (int i = 0; i < methodArgPos.length; i++) { + methodArgPos[i] = args.get(i).pos; + } + } statements = createLazyGetterBody(treeMaker, field, source); addSuppressWarningsUnchecked = LombokOptionsFactory.getDelombokOptions(field.getContext()).getFormatPreferences().generateSuppressWarnings(); } else { @@ -262,10 +270,20 @@ public class HandleGetter extends JavacAnnotationHandler { methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source, field.getContext()); if (toClearOfMarkers != null) recursiveSetGeneratedBy(toClearOfMarkers, null, null); + if (methodArgPos != null) { + for (int i = 0; i < methodArgPos.length; i++) { + ((JCMethodInvocation) toClearOfMarkers).args.get(i).pos = methodArgPos[i]; + } + } decl.mods.annotations = decl.mods.annotations.appendList(delegates); if (addSuppressWarningsUnchecked) { - addAnnotation(decl.mods, field, source.pos, source, field.getContext(), "java.lang.SuppressWarnings", treeMaker.NewArray(null, List.nil(), List.of(treeMaker.Literal("all"), treeMaker.Literal("unchecked")))); + ListBuffer suppressions = new ListBuffer(); + if (!Boolean.FALSE.equals(field.getAst().readConfiguration(ConfigurationKeys.ADD_SUPPRESSWARNINGS_ANNOTATIONS))) { + suppressions.add(treeMaker.Literal("all")); + } + suppressions.add(treeMaker.Literal("unchecked")); + addAnnotation(decl.mods, field, source.pos, source, field.getContext(), "java.lang.SuppressWarnings", treeMaker.NewArray(null, List.nil(), suppressions.toList())); } copyJavadoc(field, decl, CopyJavadoc.GETTER); diff --git a/src/core/lombok/javac/handlers/HandleJacksonized.java b/src/core/lombok/javac/handlers/HandleJacksonized.java index aff0bf63..0aa02d1b 100644 --- a/src/core/lombok/javac/handlers/HandleJacksonized.java +++ b/src/core/lombok/javac/handlers/HandleJacksonized.java @@ -149,7 +149,6 @@ public class HandleJacksonized extends JavacAnnotationHandler { // @SuperBuilder? Make it package-private! if (superBuilderAnnotationNode != null) builderClass.mods.flags = builderClass.mods.flags & ~Flags.PRIVATE; - } private String getBuilderClassName(JCAnnotation ast, JavacNode annotationNode, JavacNode annotatedNode, JCClassDecl td, AnnotationValues builderAnnotation, JavacTreeMaker maker) { diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 522f8576..3173b3ba 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -56,7 +56,7 @@ public class HandleLog { throw new UnsupportedOperationException(); } - public static void processAnnotation(LoggingFramework framework, AnnotationValues annotation, JavacNode annotationNode, String loggerTopic) { + public static void processAnnotation(LoggingFramework framework, AnnotationValues annotation, JavacNode annotationNode) { deleteAnnotationIfNeccessary(annotationNode, framework.getAnnotationClass()); JavacNode typeNode = annotationNode.up(); @@ -76,14 +76,17 @@ public class HandleLog { return; } - if (loggerTopic != null && loggerTopic.trim().isEmpty()) loggerTopic = null; + Object valueGuess = annotation.getValueGuess("topic"); + JCExpression loggerTopic = (JCExpression) annotation.getActualExpression("topic"); + + if (valueGuess instanceof String && ((String) valueGuess).trim().isEmpty()) loggerTopic = null; if (framework.getDeclaration().getParametersWithTopic() == null && loggerTopic != null) { annotationNode.addError(framework.getAnnotationAsString() + " does not allow a topic."); loggerTopic = null; } if (framework.getDeclaration().getParametersWithoutTopic() == null && loggerTopic == null) { annotationNode.addError(framework.getAnnotationAsString() + " requires a topic."); - loggerTopic = ""; + loggerTopic = typeNode.getTreeMaker().Literal(""); } JCFieldAccess loggingType = selfType(typeNode); @@ -101,7 +104,7 @@ public class HandleLog { return maker.Select(maker.Ident(name), typeNode.toName("class")); } - private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source, String logFieldName, boolean useStatic, String loggerTopic) { + private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source, String logFieldName, boolean useStatic, JCExpression loggerTopic) { JavacTreeMaker maker = typeNode.getTreeMaker(); LogDeclaration logDeclaration = framework.getDeclaration(); @@ -121,7 +124,7 @@ public class HandleLog { return true; } - private static JCExpression[] createFactoryParameters(JavacNode typeNode, JCFieldAccess loggingType, java.util.List parameters, String loggerTopic) { + private static JCExpression[] createFactoryParameters(JavacNode typeNode, JCFieldAccess loggingType, java.util.List parameters, JCExpression loggerTopic) { JCExpression[] expressions = new JCExpression[parameters.size()]; JavacTreeMaker maker = typeNode.getTreeMaker(); @@ -136,7 +139,7 @@ public class HandleLog { expressions[i] = maker.Apply(List.nil(), method, List.nil()); break; case TOPIC: - expressions[i] = maker.Literal(loggerTopic); + expressions[i] = (JCExpression) loggerTopic.clone(); break; case NULL: expressions[i] = maker.Literal(CTC_BOT, null); @@ -156,7 +159,7 @@ public class HandleLog { public static class HandleCommonsLog extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_COMMONS_FLAG_USAGE, "@apachecommons.CommonsLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.COMMONS, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.COMMONS, annotation, annotationNode); } } @@ -167,7 +170,7 @@ public class HandleLog { public static class HandleJulLog extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JUL_FLAG_USAGE, "@java.Log", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.JUL, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.JUL, annotation, annotationNode); } } @@ -178,7 +181,7 @@ public class HandleLog { public static class HandleLog4jLog extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J_FLAG_USAGE, "@Log4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.LOG4J, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.LOG4J, annotation, annotationNode); } } @@ -189,7 +192,7 @@ public class HandleLog { public static class HandleLog4j2Log extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J2_FLAG_USAGE, "@Log4j2", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.LOG4J2, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.LOG4J2, annotation, annotationNode); } } @@ -200,7 +203,7 @@ public class HandleLog { public static class HandleSlf4jLog extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_SLF4J_FLAG_USAGE, "@Slf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.SLF4J, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.SLF4J, annotation, annotationNode); } } @@ -211,7 +214,7 @@ public class HandleLog { public static class HandleXSlf4jLog extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_XSLF4J_FLAG_USAGE, "@XSlf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.XSLF4J, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.XSLF4J, annotation, annotationNode); } } @@ -222,7 +225,7 @@ public class HandleLog { public static class HandleJBossLog extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JBOSSLOG_FLAG_USAGE, "@JBossLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); - processAnnotation(LoggingFramework.JBOSSLOG, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(LoggingFramework.JBOSSLOG, annotation, annotationNode); } } @@ -233,7 +236,7 @@ public class HandleLog { public static class HandleFloggerLog extends JavacAnnotationHandler { @Override public void handle(AnnotationValues 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, ""); + processAnnotation(LoggingFramework.FLOGGER, annotation, annotationNode); } } @@ -250,7 +253,7 @@ public class HandleLog { return; } LoggingFramework framework = new LoggingFramework(lombok.CustomLog.class, logDeclaration); - processAnnotation(framework, annotation, annotationNode, annotation.getInstance().topic()); + processAnnotation(framework, annotation, annotationNode); } } } diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 2dc3247d..f6bf9e1f 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -304,7 +304,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { java.util.List> fieldNodes = new ArrayList>(); for (BuilderFieldData bfd : builderFields) { for (JavacNode f : bfd.createdFields) { - fieldNodes.add(new Included(f, null, true)); + fieldNodes.add(new Included(f, null, true, false)); } } @@ -354,8 +354,10 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } // Generate a constructor in the annotated class that takes a builder as argument. - generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, - superclassBuilderClassExpression != null); + if (!constructorExists(tdParent, builderClassName)) { + generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, + superclassBuilderClassExpression != null); + } if (isAbstract) { // Only non-abstract classes get the builder() and toBuilder() methods. @@ -375,14 +377,14 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { if (toBuilder) { switch (methodExists(TO_BUILDER_METHOD_NAME, tdParent, 0)) { case EXISTS_BY_USER: - annotationNode.addWarning("Not generating toBuilder() as it already exists."); - return; + break; case NOT_EXISTS: JCMethodDecl md = generateToBuilderMethod(cfv, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); if (md != null) { recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); injectMethod(tdParent, md); } + break; default: // Should not happen. } @@ -1070,4 +1072,33 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } return typeParameter; } + + /** + * Checks if there is a manual constructor in the given type with a single parameter (builder). + */ + private boolean constructorExists(JavacNode type, String builderClassName) { + if (type != null && type.get() instanceof JCClassDecl) { + for (JCTree def : ((JCClassDecl)type.get()).defs) { + if (def instanceof JCMethodDecl) { + JCMethodDecl md = (JCMethodDecl) def; + String name = md.name.toString(); + boolean matches = name.equals(""); + if (isTolerate(type, md)) + continue; + if (matches && md.params != null && md.params.length() == 1) { + // Cannot use typeMatches() here, because the parameter could be fully-qualified, partially-qualified, or not qualified. + // A string-compare of the last part should work. If it's a false-positive, users could still @Tolerate it. + String typeName = md.params.get(0).getType().toString(); + int lastIndexOfDot = typeName.lastIndexOf('.'); + if (lastIndexOfDot >= 0) { + typeName = typeName.substring(lastIndexOfDot+1); + } + if ((builderClassName+"").equals(typeName)) + return true; + } + } + } + } + return false; + } } diff --git a/src/core/lombok/javac/handlers/HandleUtilityClass.java b/src/core/lombok/javac/handlers/HandleUtilityClass.java index 95de4c47..5d651689 100644 --- a/src/core/lombok/javac/handlers/HandleUtilityClass.java +++ b/src/core/lombok/javac/handlers/HandleUtilityClass.java @@ -110,7 +110,7 @@ public class HandleUtilityClass extends JavacAnnotationHandler { if (typeNode.up().getKind() == Kind.COMPILATION_UNIT) markStatic = false; if (markStatic && typeNode.up().getKind() == Kind.TYPE) { JCClassDecl typeDecl = (JCClassDecl) typeNode.up().get(); - if ((typeDecl.mods.flags & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0) markStatic = false; + if ((typeDecl.mods.flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0) markStatic = false; } if (markStatic) classDecl.mods.flags |= Flags.STATIC; diff --git a/src/core/lombok/javac/handlers/HandleWith.java b/src/core/lombok/javac/handlers/HandleWith.java index 6977b10e..4e35a574 100644 --- a/src/core/lombok/javac/handlers/HandleWith.java +++ b/src/core/lombok/javac/handlers/HandleWith.java @@ -234,7 +234,8 @@ public class HandleWith extends JavacAnnotationHandler { long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext()); List annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations); - JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, annsOnParam), fieldDecl.name, fieldDecl.vartype, null); + JCExpression pType = cloneType(maker, fieldDecl.vartype, source.get(), source.getContext()); + JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, annsOnParam), fieldDecl.name, pType, null); if (!makeAbstract) { ListBuffer statements = new ListBuffer(); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index a3e876c4..efc4bf61 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -40,6 +40,7 @@ import java.util.regex.Pattern; import javax.lang.model.element.Element; +import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Scope; @@ -1127,7 +1128,25 @@ public class JavacHandlerUtil { } } } - + + static class JCAnnotationReflect { + private static Field ATTRIBUTE; + + static { + try { + ATTRIBUTE = Permit.getField(JCAnnotation.class, "attribute"); + } catch (Exception ignore) {} + } + + static Attribute.Compound getAttribute(JCAnnotation jcAnnotation) { + try { + return (Attribute.Compound) ATTRIBUTE.get(jcAnnotation); + } catch (Exception e) { + return null; + } + } + } + // jdk9 support, types have changed, names stay the same static class ClassSymbolMembersField { private static final Field membersField; @@ -1178,8 +1197,10 @@ public class JavacHandlerUtil { * Also takes care of updating the JavacAST. */ public static void injectMethod(JavacNode typeNode, JCMethodDecl method, List paramTypes, Type returnType) { + Context context = typeNode.getContext(); + Symtab symtab = Symtab.instance(context); JCClassDecl type = (JCClassDecl) typeNode.get(); - + if (method.getName().contentEquals("")) { //Scan for default constructor, and remove it. int idx = 0; @@ -1196,20 +1217,53 @@ public class JavacHandlerUtil { idx++; } } - + addSuppressWarningsAll(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext()); addGenerated(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext()); type.defs = type.defs.append(method); - - fixMethodMirror(typeNode.getContext(), typeNode.getElement(), method.getModifiers().flags, method.getName(), paramTypes, returnType); - + + List params = null; + if (method.getParameters() != null && !method.getParameters().isEmpty()) { + ListBuffer newParams = new ListBuffer(); + for (int i = 0; i < method.getParameters().size(); i++) { + JCTree.JCVariableDecl param = method.getParameters().get(i); + if (param.sym == null) { + Type paramType = paramTypes == null ? param.getType().type : paramTypes.get(i); + VarSymbol varSymbol = new VarSymbol(param.mods.flags, param.name, paramType, symtab.noSymbol); + List annotations = param.getModifiers().getAnnotations(); + if (annotations != null && !annotations.isEmpty()) { + ListBuffer newAnnotations = new ListBuffer(); + for (JCAnnotation jcAnnotation : annotations) { + Attribute.Compound attribute = JCAnnotationReflect.getAttribute(jcAnnotation); + if (attribute != null) { + newAnnotations.append(attribute); + } + } + if (annotations.length() == newAnnotations.length()) { + varSymbol.appendAttributes(newAnnotations.toList()); + } + } + newParams.append(varSymbol); + } else { + newParams.append(param.sym); + } + } + params = newParams.toList(); + if (params.length() != method.getParameters().length()) params = null; + } + + fixMethodMirror(typeNode.getContext(), typeNode.getElement(), method.getModifiers().flags, method.getName(), paramTypes, params, returnType); + typeNode.add(method, Kind.METHOD); } - - private static void fixMethodMirror(Context context, Element typeMirror, long access, Name methodName, List paramTypes, Type returnType) { + + private static void fixMethodMirror(Context context, Element typeMirror, long access, Name methodName, List paramTypes, List params, Type returnType) { if (typeMirror == null || paramTypes == null || returnType == null) return; ClassSymbol cs = (ClassSymbol) typeMirror; MethodSymbol methodSymbol = new MethodSymbol(access, methodName, new MethodType(paramTypes, returnType, List.nil(), Symtab.instance(context).methodClass), cs); + if (params != null && !params.isEmpty()) { + methodSymbol.params = params; + } ClassSymbolMembersField.enter(cs, methodSymbol); } @@ -1265,15 +1319,17 @@ public class JavacHandlerUtil { public static void addSuppressWarningsAll(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context) { if (!LombokOptionsFactory.getDelombokOptions(context).getFormatPreferences().generateSuppressWarnings()) return; - boolean addJLSuppress = true; + boolean addJLSuppress = !Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_SUPPRESSWARNINGS_ANNOTATIONS)); - for (JCAnnotation ann : mods.annotations) { - JCTree type = ann.getAnnotationType(); - Name n = null; - if (type instanceof JCIdent) n = ((JCIdent) type).name; - else if (type instanceof JCFieldAccess) n = ((JCFieldAccess) type).name; - if (n != null && n.contentEquals("SuppressWarnings")) { - addJLSuppress = false; + if (addJLSuppress) { + for (JCAnnotation ann : mods.annotations) { + JCTree type = ann.getAnnotationType(); + Name n = null; + if (type instanceof JCIdent) n = ((JCIdent) type).name; + else if (type instanceof JCFieldAccess) n = ((JCFieldAccess) type).name; + if (n != null && n.contentEquals("SuppressWarnings")) { + addJLSuppress = false; + } } } if (addJLSuppress) addAnnotation(mods, node, pos, source, context, "java.lang.SuppressWarnings", node.getTreeMaker().Literal("all")); @@ -1520,6 +1576,20 @@ public class JavacHandlerUtil { * Searches the given field node for annotations that are specifically intentioned to be copied to the setter. */ public static List findCopyableToSetterAnnotations(JavacNode node) { + return findAnnotationsInList(node, COPY_TO_SETTER_ANNOTATIONS); + } + + /** + * Searches the given field node for annotations that are specifically intentioned to be copied to the builder's singular method. + */ + public static List findCopyableToBuilderSingularSetterAnnotations(JavacNode node) { + return findAnnotationsInList(node, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS); + } + + /** + * Searches the given field node for annotations that are in the given list, and returns those. + */ + private static List findAnnotationsInList(JavacNode node, java.util.List annotationsToFind) { JCAnnotation anno = null; String annoName = null; for (JavacNode child : node.down()) { @@ -1537,7 +1607,7 @@ public class JavacHandlerUtil { if (annoName == null) return List.nil(); if (!annoName.isEmpty()) { - for (String bn : COPY_TO_SETTER_ANNOTATIONS) if (typeMatches(bn, node, anno.annotationType)) return List.of(anno); + for (String bn : annotationsToFind) if (typeMatches(bn, node, anno.annotationType)) return List.of(anno); } ListBuffer result = new ListBuffer(); @@ -1545,7 +1615,7 @@ public class JavacHandlerUtil { if (child.getKind() == Kind.ANNOTATION) { JCAnnotation annotation = (JCAnnotation) child.get(); boolean match = false; - if (!match) for (String bn : COPY_TO_SETTER_ANNOTATIONS) if (typeMatches(bn, node, annotation.annotationType)) { + if (!match) for (String bn : annotationsToFind) if (typeMatches(bn, node, annotation.annotationType)) { result.append(annotation); break; } @@ -1935,6 +2005,7 @@ public class JavacHandlerUtil { } private static final Pattern SECTION_FINDER = Pattern.compile("^\\s*\\**\\s*[-*][-*]+\\s*([GS]ETTER|WITH(?:ER)?)\\s*[-*][-*]+\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + private static final Pattern LINE_BREAK_FINDER = Pattern.compile("(\\r?\\n)?"); public static String stripLinesWithTagFromJavadoc(String javadoc, String regexpFragment) { Pattern p = Pattern.compile("^\\s*\\**\\s*" + regexpFragment + "\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); @@ -1943,27 +2014,29 @@ public class JavacHandlerUtil { } public static String stripSectionsFromJavadoc(String javadoc) { - Matcher m = SECTION_FINDER.matcher(javadoc); - if (!m.find()) return javadoc; + Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); + if (!sectionMatcher.find()) return javadoc; - return javadoc.substring(0, m.start()); + return javadoc.substring(0, sectionMatcher.start()); } public static String getJavadocSection(String javadoc, String sectionNameSpec) { String[] sectionNames = sectionNameSpec.split("\\|"); - Matcher m = SECTION_FINDER.matcher(javadoc); + Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); + Matcher lineBreakMatcher = LINE_BREAK_FINDER.matcher(javadoc); int sectionStart = -1; int sectionEnd = -1; - while (m.find()) { + while (sectionMatcher.find()) { boolean found = false; - for (String sectionName : sectionNames) if (m.group(1).equalsIgnoreCase(sectionName)) { + for (String sectionName : sectionNames) if (sectionMatcher.group(1).equalsIgnoreCase(sectionName)) { found = true; break; } if (found) { - sectionStart = m.end() + 1; + lineBreakMatcher.find(sectionMatcher.end()); + sectionStart = lineBreakMatcher.end(); } else if (sectionStart != -1) { - sectionEnd = m.start(); + sectionEnd = sectionMatcher.start(); } } diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index ba052b5a..7cd52c8c 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -182,11 +182,12 @@ public class JavacSingularsRecipes { return this; } - protected JCModifiers makeMods(JavacTreeMaker maker, CheckerFrameworkVersion cfv, JavacNode node, boolean deprecate, AccessLevel access) { + protected JCModifiers makeMods(JavacTreeMaker maker, CheckerFrameworkVersion cfv, JavacNode node, boolean deprecate, AccessLevel access, List methodAnnotations) { JCAnnotation deprecateAnn = deprecate ? maker.Annotation(genJavaLangTypeRef(node, "Deprecated"), List.nil()) : null; JCAnnotation rrAnn = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(node, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; List annsOnMethod = (deprecateAnn != null && rrAnn != null) ? List.of(deprecateAnn, rrAnn) : deprecateAnn != null ? List.of(deprecateAnn) : rrAnn != null ? List.of(rrAnn) : List.nil(); + annsOnMethod = mergeAnnotations(annsOnMethod,methodAnnotations); return maker.Modifiers(toJavacModifier(access), annsOnMethod); } @@ -271,10 +272,10 @@ public class JavacSingularsRecipes { generateClearMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, access); } - private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, AccessLevel access, Boolean ignoreNullCollections) { + private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, List methodAnnotations, AccessLevel access, Boolean ignoreNullCollections) { if (returnStatement != null) statements.append(returnStatement); JCBlock body = maker.Block(0, statements.toList()); - JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access); + JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access, methodAnnotations); List typeParams = List.nil(); List thrown = List.nil(); @@ -298,7 +299,7 @@ public class JavacSingularsRecipes { statements.add(clearStatement); Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); - finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.nil(), access, null); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.nil(), List.nil(), access, null); } protected abstract JCStatement generateClearStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType); @@ -312,7 +313,8 @@ public class JavacSingularsRecipes { if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(setterPrefix, name.toString())); statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source)); - finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, access, null); + List methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up())); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, methodAnnotations, access, null); } protected JCVariableDecl generateSingularMethodParameter(int typeIndex, JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, Name name) { @@ -357,8 +359,10 @@ public class JavacSingularsRecipes { } else { statements.prepend(JavacHandlerUtil.generateNullCheck(maker, null, data.getPluralName(), builderType, "%s cannot be null")); } + + List methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up())); - finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), access, ignoreNullCollections); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), methodAnnotations, access, ignoreNullCollections); } protected ListBuffer generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { diff --git a/src/core/lombok/javac/apt/Javac9BaseFileObjectWrapper.java b/src/core8/lombok/javac/apt/Javac9BaseFileObjectWrapper.java similarity index 100% rename from src/core/lombok/javac/apt/Javac9BaseFileObjectWrapper.java rename to src/core8/lombok/javac/apt/Javac9BaseFileObjectWrapper.java diff --git a/src/core8/lombok/javac/apt/Javac9Compiler.java b/src/core8/lombok/javac/apt/Javac9Compiler.java new file mode 100644 index 00000000..c02e5929 --- /dev/null +++ b/src/core8/lombok/javac/apt/Javac9Compiler.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2010-2020 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.apt; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Iterator; +import java.util.Set; + +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; + +import com.sun.tools.javac.file.BaseFileManager; + +class Java9Compiler implements lombok.javac.apt.LombokFileObjects.Compiler { + private final BaseFileManager fileManager; + + public Java9Compiler(JavaFileManager jfm) { + fileManager = asBaseFileManager(jfm); + } + + @Override public JavaFileObject wrap(LombokFileObject fileObject) { + Path p; try { + p = toPath(fileObject); + } catch (Exception e) { + p = null; + } + + // J9BFOW extends javac's internal file base impl of javax.tools.JavaFileObject. + // J9JFOW just straight implements it. Probably J9JFOW is fine, but we decided to extend java's internal impl possibly for a reason. + // Some exotic build environments don't _have_ file objects and crash with FileNotFoundEx, so if that happens, let's try the alternative. + if (p != null) return new Javac9BaseFileObjectWrapper(fileManager, p, fileObject); + return new Javac9JavaFileObjectWrapper(fileObject); + } + + @Override public Method getDecoderMethod() { + return null; + } + + private static Path toPath(LombokFileObject fileObject) { + URI uri = fileObject.toUri(); + if (uri.getScheme() == null) { + uri = URI.create("file:///" + uri); + } + try { + return Paths.get(uri); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Problems in URI '" + uri + "' (" + fileObject.toUri() + ")", e); + } + } + + private static BaseFileManager asBaseFileManager(JavaFileManager jfm) { + if (jfm instanceof BaseFileManager) { + return (BaseFileManager) jfm; + } + return new FileManagerWrapper(jfm); + } + + static class FileManagerWrapper extends BaseFileManager { + JavaFileManager manager; + + public FileManagerWrapper(JavaFileManager manager) { + super(null); + this.manager = manager; + } + + @Override + public int isSupportedOption(String option) { + return manager.isSupportedOption(option); + } + + @Override + public ClassLoader getClassLoader(Location location) { + return manager.getClassLoader(location); + } + + @Override + public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { + return manager.list(location, packageName, kinds, recurse); + } + + @Override + public String inferBinaryName(Location location, JavaFileObject file) { + return manager.inferBinaryName(location, file); + } + + @Override + public boolean isSameFile(FileObject a, FileObject b) { + return manager.isSameFile(a, b); + } + + @Override + public boolean handleOption(String current, Iterator remaining) { + return manager.handleOption(current, remaining); + } + + @Override + public boolean hasLocation(Location location) { + return manager.hasLocation(location); + } + + @Override + public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { + return manager.getJavaFileForInput(location, className, kind); + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { + return manager.getJavaFileForOutput(location, className, kind, sibling); + } + + @Override + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { + return manager.getFileForInput(location, packageName, relativeName); + } + + @Override + public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + return manager.getFileForOutput(location, packageName, relativeName, sibling); + } + + @Override + public void flush() throws IOException { + manager.flush(); + } + + @Override + public void close() throws IOException { + manager.close(); + } + } +} diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 2db70f7f..54fa4ebf 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -188,12 +188,6 @@ public class PrettyPrinter extends JCTree.Visitor { return getEndPosition(tree, compilationUnit); } - private static int lineEndPos(String s, int start) { - int pos = s.indexOf('\n', start); - if (pos < 0) pos = s.length(); - return pos; - } - private boolean needsAlign, needsNewLine, onNewLine = true, needsSpace, aligned; public static final class UncheckedIOException extends RuntimeException { @@ -434,23 +428,25 @@ public class PrettyPrinter extends JCTree.Visitor { private void printDocComment(JCTree tree) { String dc = getJavadocFor(tree); if (dc == null) return; + aPrintln("/**"); - int pos = 0; - int endpos = lineEndPos(dc, pos); boolean atStart = true; - while (pos < dc.length()) { - String line = dc.substring(pos, endpos); - if (line.trim().isEmpty() && atStart) { + + for (String line : dc.split("\\r?\\n")) { + if (atStart && line.trim().isEmpty()) { atStart = false; continue; } + atStart = false; aPrint(" *"); - if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); - println(dc.substring(pos, endpos)); - pos = endpos + 1; - endpos = lineEndPos(dc, pos); + if (!line.isEmpty() && !Character.isWhitespace(line.charAt(0))) { + print(" "); + } + + println(line); } + aPrintln(" */"); } @@ -796,8 +792,15 @@ public class PrettyPrinter extends JCTree.Visitor { print(tree.name); } - print("("); boolean first = true; + print("("); + + JCVariableDecl recvparam = readObject(tree, "recvparam", null); + if (recvparam != null) { + printVarDefInline(recvparam); + first = false; + } + for (JCVariableDecl param : tree.params) { if (!first) print(", "); first = false; @@ -1316,7 +1319,7 @@ public class PrettyPrinter extends JCTree.Visitor { print(";"); needsNewLine = true; needsAlign = true; - } else if (tree.stats.head.getClass().getSimpleName().equals("JCYield")) { + } else if (tree.stats.head.getClass().getName().endsWith("$JCYield")) { print((JCExpression) readObject(tree.stats.head, "value", null)); print(";"); needsNewLine = true; @@ -1593,25 +1596,25 @@ public class PrettyPrinter extends JCTree.Visitor { } @Override public void visitTree(JCTree tree) { - String simpleName = tree.getClass().getSimpleName(); - if ("JCTypeUnion".equals(simpleName)) { + String className = tree.getClass().getName(); + if (className.endsWith("$JCTypeUnion")) { List types = readObject(tree, "alternatives", List.nil()); print(types, " | "); - } else if ("JCTypeIntersection".equals(simpleName)) { + } else if (className.endsWith("$JCTypeIntersection")) { print(readObject(tree, "bounds", List.nil()), " & "); - } else if ("JCMemberReference".equals(simpleName)) { + } else if (className.endsWith("$JCMemberReference")) { printMemberReference0(tree); - } else if ("JCLambda".equals(simpleName)) { + } else if (className.endsWith("$JCLambda")) { printLambda0(tree); - } else if ("JCAnnotatedType".equals(simpleName)) { + } else if (className.endsWith("$JCAnnotatedType")) { printAnnotatedType0(tree); - } else if ("JCPackageDecl".equals(simpleName)) { + } else if (className.endsWith("$JCPackageDecl")) { // Starting with JDK9, this is inside the import list, but we've already printed it. Just ignore it. - } else if ("JCSwitchExpression".equals(simpleName)) { // Introduced as preview feature in JDK12 + } else if (className.endsWith("$JCSwitchExpression")) { // Introduced as preview feature in JDK12 printSwitchExpression(tree); - } else if ("JCYield".equals(simpleName)) { // Introduced as preview feature in JDK13, part of switch expressions. + } else if (className.endsWith("$JCYield")) { // Introduced as preview feature in JDK13, part of switch expressions. printYieldExpression(tree); - } else if ("JCBindingPattern".equals(simpleName)) { // Introduced as preview in JDK14 + } else if (className.endsWith("$JCBindingPattern")) { // Introduced as preview in JDK14 printBindingPattern(tree); } else { throw new AssertionError("Unhandled tree type: " + tree.getClass() + ": " + tree); @@ -1631,7 +1634,7 @@ public class PrettyPrinter extends JCTree.Visitor { if (o == null) return false; if (jcAnnotatedTypeInit) return jcAnnotatedTypeClass == o.getClass(); Class c = o.getClass(); - if (c.getSimpleName().equals("JCAnnotatedType")) { + if (c.getName().endsWith("$JCAnnotatedType")) { jcAnnotatedTypeClass = c; jcAnnotatedTypeInit = true; return true; diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 756c23fa..c560f002 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -103,6 +103,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchIdentifierEndReparse(sm); patchRetrieveEllipsisStartPosition(sm); patchRetrieveRightBraceOrSemiColonPosition(sm); + patchRetrieveProperRightBracketPosition(sm); patchSetGeneratedFlag(sm); patchDomAstReparseIssues(sm); patchHideGeneratedNodes(sm); @@ -445,6 +446,16 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { // .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build()); } + private static void patchRetrieveProperRightBracketPosition(ScriptManager sm) { + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "extractSubArrayType", "org.eclipse.jdt.core.dom.ArrayType", "org.eclipse.jdt.core.dom.ArrayType", "int", "int")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.ASTConverter", "retrieveProperRightBracketPosition", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveProperRightBracketPosition", "int", "int", "org.eclipse.jdt.core.dom.ArrayType")) + .requestExtra(StackRequest.PARAM1) + .transplant() + .build()); + } + private static void patchSetGeneratedFlag(ScriptManager sm) { sm.addScript(ScriptBuilder.addField() .targetClass("org.eclipse.jdt.internal.compiler.ast.ASTNode") @@ -564,6 +575,22 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); + + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setTypeNameForAnnotation", "void", "org.eclipse.jdt.internal.compiler.ast.Annotation", "org.eclipse.jdt.core.dom.Annotation")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "", "void", "org.eclipse.jdt.core.dom.AST")) + .requestExtra(StackRequest.PARAM1) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", + "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) + .transplant().build()); + + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setTypeNameForAnnotation", "void", "org.eclipse.jdt.internal.compiler.ast.Annotation", "org.eclipse.jdt.core.dom.Annotation")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.QualifiedName", "", "void", "org.eclipse.jdt.core.dom.AST")) + .requestExtra(StackRequest.PARAM1) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", + "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) + .transplant().build()); } private static void patchAvoidReparsingGeneratedCode(ScriptManager sm) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java index 02760e35..1a287d93 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java @@ -29,11 +29,14 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import lombok.core.AST.Kind; +import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAST; import lombok.eclipse.EclipseNode; import lombok.eclipse.TransformEclipseAST; @@ -67,6 +70,7 @@ import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; @@ -214,7 +218,7 @@ public class PatchDelegate { addAllMethodBindings(methodsToExclude, cla.type.resolveType(decl.initializerScope), new HashSet(), field.name, ann); } - Set banList = new HashSet(); + Set banList = findAlreadyImplementedMethods(decl); for (BindingTuple excluded : methodsToExclude) banList.add(printSig(excluded.parameterized)); if (rawTypes.isEmpty()) { @@ -283,8 +287,8 @@ public class PatchDelegate { for (ClassLiteralAccess cla : excludedRawTypes) { addAllMethodBindings(methodsToExclude, cla.type.resolveType(decl.initializerScope), new HashSet(), method.selector, ann); } - - Set banList = new HashSet(); + + Set banList = findAlreadyImplementedMethods(decl); for (BindingTuple excluded : methodsToExclude) banList.add(printSig(excluded.parameterized)); if (rawTypes.isEmpty()) { @@ -317,6 +321,8 @@ public class PatchDelegate { private static boolean isDelegate(Annotation ann, TypeDeclaration decl) { if (ann.type == null) return false; + if (!charArrayEquals("Delegate", ann.type.getLastToken())) return false; + TypeBinding tb = ann.type.resolveType(decl.initializerScope); if (tb == null) return false; if (!charArrayEquals("lombok", tb.qualifiedPackageName()) && !charArrayEquals("lombok.experimental", tb.qualifiedPackageName())) return false; @@ -764,6 +770,21 @@ public class PatchDelegate { } } + private static Set findAlreadyImplementedMethods(TypeDeclaration decl) { + Set sigs = new HashSet(); + for (AbstractMethodDeclaration md : decl.methods) { + if (md.isStatic()) continue; + if ((md.modifiers & ClassFileConstants.AccBridge) != 0) continue; + if (md.isConstructor()) continue; + if ((md.modifiers & ExtraCompilerModifiers.AccDefaultAbstract) != 0) continue; + if ((md.modifiers & ClassFileConstants.AccPublic) == 0) continue; + if ((md.modifiers & ClassFileConstants.AccSynthetic) != 0) continue; + + sigs.add(printSig(md, decl.scope)); + } + return sigs; + } + private static final char[] STRING_LOMBOK = new char[] {'l', 'o', 'm', 'b', 'o', 'k'}; private static final char[] STRING_EXPERIMENTAL = new char[] {'e', 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l'}; private static final char[] STRING_DELEGATE = new char[] {'D', 'e', 'l', 'e', 'g', 'a', 't', 'e'}; @@ -839,6 +860,54 @@ public class PatchDelegate { return signature.toString(); } + private static String printSig(AbstractMethodDeclaration md, ClassScope scope) { + StringBuilder signature = new StringBuilder(); + + signature.append(md.selector); + signature.append("("); + boolean first = true; + if (md.arguments != null) { + TypeParameter[] typeParameters = md.typeParameters(); + Map typeParametersMap = new HashMap(); + if (typeParameters != null) { + for (TypeParameter typeParameter : typeParameters) { + typeParametersMap.put(new String(typeParameter.name), typeParameter); + } + } + + for (Argument argument : md.arguments) { + TypeBinding typeBinding = makeTypeBinding(argument.type, typeParametersMap, scope); + + if (!first) signature.append(", "); + first = false; + signature.append(typeBindingToSignature(typeBinding)); + } + } + signature.append(")"); + + return signature.toString(); + } + + private static TypeBinding makeTypeBinding(TypeReference typeReference, Map typeParametersMap, ClassScope scope) { + char[][] typeName = typeReference.getTypeName(); + String typeNameString = Eclipse.toQualifiedName(typeName); + + TypeParameter typeParameter = typeParametersMap.get(typeNameString); + if (typeParameter != null) { + if (typeParameter.type != null) { + typeName = typeParameter.type.getTypeName(); + } else { + typeName = TypeConstants.JAVA_LANG_OBJECT; + } + } + + TypeBinding typeBinding = scope.getType(typeName, typeName.length); + if (typeReference.dimensions() > 0) { + typeBinding = scope.createArrayType(typeBinding, typeReference.dimensions()); + } + return typeBinding; + } + private static String typeBindingToSignature(TypeBinding binding) { binding = binding.erasure(); if (binding != null && binding.isBaseType()) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 056852c8..f22e78a8 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -35,11 +35,13 @@ import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression; import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; @@ -227,14 +229,16 @@ public class PatchVal { boolean var = isVar(local, scope); if (!(val || var)) return false; - StackTraceElement[] st = new Throwable().getStackTrace(); - for (int i = 0; i < st.length - 2 && i < 10; i++) { - if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) { - boolean valInForStatement = val && - st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && - st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement"); - if (valInForStatement) return false; - break; + if (val) { + StackTraceElement[] st = new Throwable().getStackTrace(); + for (int i = 0; i < st.length - 2 && i < 10; i++) { + if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) { + boolean valInForStatement = + st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && + st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement"); + if (valInForStatement) return false; + break; + } } } @@ -264,6 +268,7 @@ public class PatchVal { } TypeBinding resolved = null; + Constant oldConstant = init.constant; try { resolved = decomponent ? getForEachComponentType(init, scope) : resolveForExpression(init, scope); } catch (NullPointerException e) { @@ -280,6 +285,10 @@ public class PatchVal { } catch (Exception e) { // Some type thing failed. } + } else { + if (init instanceof MessageSend && ((MessageSend) init).actualReceiverType == null) { + init.constant = oldConstant; + } } } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index 563beab1..deab0be1 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -38,6 +38,7 @@ import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.search.SearchMatch; @@ -517,6 +518,12 @@ final class PatchFixesHider { return -1; } + public static int fixRetrieveProperRightBracketPosition(int retVal, ArrayType arrayType) { + if (retVal != -1 || arrayType == null) return retVal; + if (isGenerated(arrayType)) return arrayType.getStartPosition() + arrayType.getLength() - 1; + return -1; + } + public static final int ALREADY_PROCESSED_FLAG = 0x800000; //Bit 24 public static boolean checkBit24(Object node) throws Exception { diff --git a/src/installer/lombok/installer/IdeLocation.java b/src/installer/lombok/installer/IdeLocation.java index c3853867..6b9a94c6 100644 --- a/src/installer/lombok/installer/IdeLocation.java +++ b/src/installer/lombok/installer/IdeLocation.java @@ -66,7 +66,7 @@ public abstract class IdeLocation { } private static final String LEGAL_PATH_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/"; - private static final String LEGAL_PATH_CHARS_WINDOWS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/:\\ "; + private static final String LEGAL_PATH_CHARS_WINDOWS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,/;'[]{}!@#$^&()-_+= :\\"; public static String escapePath(String path) { StringBuilder out = new StringBuilder(); String legalChars = OsUtils.getOS() == OsUtils.OS.UNIX ? LEGAL_PATH_CHARS : LEGAL_PATH_CHARS_WINDOWS; diff --git a/src/launch/lombok/launch/ShadowClassLoader.java b/src/launch/lombok/launch/ShadowClassLoader.java index 30ca6e97..da377ae4 100644 --- a/src/launch/lombok/launch/ShadowClassLoader.java +++ b/src/launch/lombok/launch/ShadowClassLoader.java @@ -321,8 +321,9 @@ class ShadowClassLoader extends ClassLoader { } private static String urlDecode(String in) { + final String plusFixed = in.replaceAll("\\+", "%2B"); try { - return URLDecoder.decode(in, "UTF-8"); + return URLDecoder.decode(plusFixed, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new InternalError("UTF-8 not supported"); } diff --git a/src/stubs/com/sun/tools/javac/code/Symbol.java b/src/stubs/com/sun/tools/javac/code/Symbol.java index 4aef63ad..15b04148 100644 --- a/src/stubs/com/sun/tools/javac/code/Symbol.java +++ b/src/stubs/com/sun/tools/javac/code/Symbol.java @@ -18,12 +18,13 @@ import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; +import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; public abstract class Symbol implements Element { public Type type; public Name name; - + public long flags() { return 0; } public boolean isStatic() { return false; } public boolean isConstructor() { return false; } @@ -37,10 +38,13 @@ public abstract class Symbol implements Element { @Override public Name getSimpleName() { return null; } @Override public java.util.List getEnclosedElements() { return null; } @Override public Element getEnclosingElement() { return null; } - + public void appendAttributes(List l) { + } + public static abstract class TypeSymbol extends Symbol {} public static class MethodSymbol extends Symbol implements ExecutableElement { + public List params = null; public MethodSymbol(long flags, Name name, Type type, Symbol owner) {} @Override public ElementKind getKind() { return null; } @Override public Set getModifiers() { return null; } @@ -58,6 +62,8 @@ public abstract class Symbol implements Element { public static class VarSymbol extends Symbol implements VariableElement { public Type type; + public VarSymbol(long flags, Name name, Type type, Symbol owner) { + } @Override public ElementKind getKind() { return null; } @Override public Set getModifiers() { return null; } @Override public R accept(ElementVisitor v, P p) { return null; } diff --git a/src/stubs/com/sun/tools/javac/code/Symtab.java b/src/stubs/com/sun/tools/javac/code/Symtab.java index 2b524e4c..8d823531 100644 --- a/src/stubs/com/sun/tools/javac/code/Symtab.java +++ b/src/stubs/com/sun/tools/javac/code/Symtab.java @@ -5,6 +5,7 @@ package com.sun.tools.javac.code; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.ModuleSymbol; +import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.util.Context; public class Symtab { @@ -14,6 +15,7 @@ public class Symtab { public Type objectType; public static Symtab instance(Context context) {return null;} public Type unknownType; + public TypeSymbol noSymbol; // JDK 9 public ModuleSymbol unnamedModule; diff --git a/src/stubs/java/lang/annotation/ElementType.java b/src/stubs/java/lang/annotation/ElementType.java new file mode 100644 index 00000000..bbab9cda --- /dev/null +++ b/src/stubs/java/lang/annotation/ElementType.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.annotation; + +/** + * The constants of this enumerated type provide a simple classification of the + * syntactic locations where annotations may appear in a Java program. These + * constants are used in {@link java.lang.annotation.Target Target} + * meta-annotations to specify where it is legal to write annotations of a + * given type. + * + *

The syntactic locations where annotations may appear are split into + * declaration contexts , where annotations apply to declarations, and + * type contexts , where annotations apply to types used in + * declarations and expressions. + * + *

The constants {@link #ANNOTATION_TYPE}, {@link #CONSTRUCTOR}, {@link + * #FIELD}, {@link #LOCAL_VARIABLE}, {@link #METHOD}, {@link #PACKAGE}, {@link + * #MODULE}, {@link #PARAMETER}, {@link #TYPE}, and {@link #TYPE_PARAMETER} + * correspond to the declaration contexts in JLS 9.6.4.1. + * + *

For example, an annotation whose type is meta-annotated with + * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a + * field declaration. + * + *

The constant {@link #TYPE_USE} corresponds to the type contexts in JLS + * 4.11, as well as to two declaration contexts: type declarations (including + * annotation type declarations) and type parameter declarations. + * + *

For example, an annotation whose type is meta-annotated with + * {@code @Target(ElementType.TYPE_USE)} may be written on the type of a field + * (or within the type of the field, if it is a nested, parameterized, or array + * type), and may also appear as a modifier for, say, a class declaration. + * + *

The {@code TYPE_USE} constant includes type declarations and type + * parameter declarations as a convenience for designers of type checkers which + * give semantics to annotation types. For example, if the annotation type + * {@code NonNull} is meta-annotated with + * {@code @Target(ElementType.TYPE_USE)}, then {@code @NonNull} + * {@code class C {...}} could be treated by a type checker as indicating that + * all variables of class {@code C} are non-null, while still allowing + * variables of other classes to be non-null or not non-null based on whether + * {@code @NonNull} appears at the variable's declaration. + * + * @author Joshua Bloch + * @since 1.5 + * @jls 9.6.4.1 @Target + * @jls 4.1 The Kinds of Types and Values + */ +public enum ElementType { + /** Class, interface (including annotation type), or enum declaration */ + TYPE, + + /** Field declaration (includes enum constants) */ + FIELD, + + /** Method declaration */ + METHOD, + + /** Formal parameter declaration */ + PARAMETER, + + /** Constructor declaration */ + CONSTRUCTOR, + + /** Local variable declaration */ + LOCAL_VARIABLE, + + /** Annotation type declaration */ + ANNOTATION_TYPE, + + /** Package declaration */ + PACKAGE, + + /** + * Type parameter declaration + * + * @since 1.8 + */ + TYPE_PARAMETER, + + /** + * Use of a type + * + * @since 1.8 + */ + TYPE_USE, + + /** + * Module declaration. + * + * @since 9 + */ + MODULE +} diff --git a/src/stubsstubs/java/nio/file/Path.java b/src/stubsstubs/java/nio/file/Path.java new file mode 100644 index 00000000..5fb2e7ec --- /dev/null +++ b/src/stubsstubs/java/nio/file/Path.java @@ -0,0 +1,4 @@ +package java.nio.file; + +public class Path { +} diff --git a/src/support/info.txt b/src/support/info.txt new file mode 100644 index 00000000..1723bffe --- /dev/null +++ b/src/support/info.txt @@ -0,0 +1,4 @@ +These classes are not part of lombok itself, but used during the build. For example: +* Code to turn the changelog into HTML ready to ship to projectlombok.org +* Code to create eclipse debug targets + diff --git a/src/website/log4j.properties b/src/support/log4j.properties similarity index 100% rename from src/website/log4j.properties rename to src/support/log4j.properties diff --git a/src/support/lombok/eclipseCreate/CreateEclipseDebugTarget.java b/src/support/lombok/eclipseCreate/CreateEclipseDebugTarget.java new file mode 100644 index 00000000..e5e48c49 --- /dev/null +++ b/src/support/lombok/eclipseCreate/CreateEclipseDebugTarget.java @@ -0,0 +1,194 @@ +package lombok.eclipseCreate; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Pattern; + +public class CreateEclipseDebugTarget { + private Map args; + private StringBuilder launchContent = new StringBuilder(); + + private static class InvalidCommandLineException extends Exception { + InvalidCommandLineException(String msg) { + super(msg); + + } + InvalidCommandLineException(String msg, Throwable cause) { + super(msg, cause); + } + } + + public static void main(String[] args) throws Exception { + CreateEclipseDebugTarget instance = new CreateEclipseDebugTarget(); + try { + instance.args = parseArgs(args); + if (instance.args.isEmpty()) throw new InvalidCommandLineException(""); + instance.go(); + } catch (InvalidCommandLineException e) { + String msg = e.getMessage(); + if (!msg.isEmpty()) System.err.println("ERROR: " + msg); + if (e.getCause() != null) { + e.getCause().printStackTrace(); + } + printCommandLineHelp(); + System.exit(1); + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void go() throws InvalidCommandLineException, IOException { + prologue(); + classpath(); + epilogue(); + String n = getArgString("name"); + File f = new File(n + ".launch").getCanonicalFile(); + + OutputStream out = new FileOutputStream(f); + try { + out.write(launchContent.toString().getBytes("UTF-8")); + } finally { + out.close(); + } + + System.out.println("Debug target created: " + f); + } + + private void prologue() throws InvalidCommandLineException { + String type = getArgString("testType"); + + launchContent.append("\n"); + launchContent.append("\n"); + launchContent.append("\t\n"); + launchContent.append("\t\t\n"); + launchContent.append("\t\n"); + launchContent.append("\t\n"); + launchContent.append("\t\t\n"); + launchContent.append("\t\n"); + + if (getArgBoolean("favorite")) { + launchContent.append("\t\n"); + launchContent.append("\t\t\n"); + launchContent.append("\t\n"); + } + + launchContent.append("\t\n"); + launchContent.append("\t\n"); + launchContent.append("\t\n"); + launchContent.append("\t\n"); + launchContent.append("\t\n"); + } + + private void classpath() throws InvalidCommandLineException { + launchContent.append("\t\n"); + + String self; try { + self = new File("..").getCanonicalPath(); + } catch (IOException e) { + throw new InvalidCommandLineException("Cannot obtain canonical path to parent directory", e); + } + + String bootpath = getBootPath(); + + launchContent.append("\t\t\n"); + for (Map.Entry entry : args.entrySet()) { + if (!entry.getKey().startsWith("conf.")) continue; + String[] files = entry.getValue().split(Pattern.quote(File.pathSeparator)); + for (String file : files) { + String n; + try { + n = new File(file).getCanonicalPath(); + } catch (IOException e) { + throw new InvalidCommandLineException("Cannot obtain canonical path to dependency " + file, e); + } + if (n.startsWith(self)) { + launchContent.append("\t\t\n"); + } + } + } + if (bootpath != null) launchContent.append("\t\t\n"); + launchContent.append("\t\n"); + } + + private void epilogue() throws InvalidCommandLineException { + String type = getArgString("testType"); + + launchContent.append("\t\n"); + String jvmTarget = getArgString("jvmTarget"); + String bootpath = getBootPath(); + launchContent.append("\t\n"); + launchContent.append("\t\n"); + launchContent.append("\t\n"); + launchContent.append("\t\n"); + if (getArgBoolean("shadowLoaderBased")) { + launchContent.append(" entry : args.entrySet()) { + if (!entry.getKey().startsWith("conf.")) continue; + launchContent.append(File.pathSeparator).append(entry.getValue()); + } + if (bootpath != null) launchContent.append(" -Ddelombok.bootclasspath=" + bootpath); + } + launchContent.append("\"/>\n\n"); + } + + private String getBootPath() { + String bp = args.get("bootpath"); + if (bp == null || bp.isEmpty() || bp.equals("0")) return null; + File f = new File(bp); + if (!f.isAbsolute()) return bp; + String r = new File(".").getAbsolutePath(); + if (r.endsWith(".")) r = r.substring(0, r.length() - 1); + if (bp.startsWith(r)) return bp.substring(r.length()); + throw new IllegalStateException("Cannot reconstruct relative path; base: " + r + " is not a parent of " + bp); + } + + private String getArgString(String key) throws InvalidCommandLineException { + String v = args.get(key); + if (v == null) throw new InvalidCommandLineException("mandatory argument '" + key + "' missing"); + return v; + } + + private boolean getArgBoolean(String key) throws InvalidCommandLineException { + String v = args.get(key); + if (v == null) return false; + if (v.equalsIgnoreCase("false") || v.equalsIgnoreCase("f")) return false; + return true; + } + + private static void printCommandLineHelp() { + System.err.println("CreateEclipseDebugTarget\n" + + " name=Lombok-test BaseJavac 11 # Sets the name of the debug target to make\n" + + " testType=lombok.RunJavacAndBaseTests # The test class file that this debug target should run\n" + + " shadowLoaderBased # Add the VM options to use lombok as an agent and pass the classpath to the shadow loader. Needed for ECJ/Eclipse.\n" + + " conf.test=foo:bar:baz # Where 'test' is an ivy conf name, and 'foo' is a path to a jar, relativized vs. current directory.\n" + + " favorite # Should the debug target be marked as favourite?\n" + + ""); + } + + private static Map parseArgs(String[] args) throws IllegalArgumentException { + Map map = new LinkedHashMap(); + + for (String arg : args) { + int idx = arg.indexOf('='); + String key = (idx == -1 ? arg : arg.substring(0, idx)).trim(); + String value = (idx == -1 ? "" : arg.substring(idx + 1)).trim(); + String existing = map.get(key); + if (existing != null) { + if (key.startsWith("conf.")) { + value = existing + File.pathSeparator + value; + } else { + throw new IllegalArgumentException("Duplicate argument not allowed: " + key); + } + } + map.put(key, value); + } + return map; + } +} \ No newline at end of file diff --git a/src/website/lombok/website/CompileChangelog.java b/src/support/lombok/website/CompileChangelog.java similarity index 100% rename from src/website/lombok/website/CompileChangelog.java rename to src/support/lombok/website/CompileChangelog.java diff --git a/src/support/lombok/website/Domain.java b/src/support/lombok/website/Domain.java new file mode 100644 index 00000000..103c7377 --- /dev/null +++ b/src/support/lombok/website/Domain.java @@ -0,0 +1,26 @@ +package lombok.website; + +import java.net.MalformedURLException; +import java.net.URL; + +public class Domain { + private static final String DEFAULT = "https://projectlombok.org/"; + private final String prefix; + + public Domain(String arg) { + if (arg == null || arg.isEmpty()) this.prefix = DEFAULT; + else { + if (!arg.contains("://")) arg = "https://" + arg; + if (!arg.endsWith("/")) arg += "/"; + this.prefix = arg; + } + } + + public String getPrefix() { + return prefix; + } + + public URL url(String path) throws MalformedURLException { + return new URL(prefix + path); + } +} diff --git a/src/website/lombok/website/FetchCurrentVersion.java b/src/support/lombok/website/FetchCurrentVersion.java similarity index 79% rename from src/website/lombok/website/FetchCurrentVersion.java rename to src/support/lombok/website/FetchCurrentVersion.java index d32c45dd..ec8d833a 100644 --- a/src/website/lombok/website/FetchCurrentVersion.java +++ b/src/support/lombok/website/FetchCurrentVersion.java @@ -4,7 +4,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -14,11 +13,11 @@ public class FetchCurrentVersion { private static final Pattern VERSION_PATTERN = Pattern.compile("^.*<\\s*span\\s+id\\s*=\\s*[\"'](currentVersion|currentVersionFull)[\"'](?:\\s+style\\s*=\\s*[\"']display\\s*:\\s*none;?[\"'])?\\s*>\\s*([^\t<]+)\\s*<\\s*/\\s*span\\s*>.*$"); public static void main(String[] args) throws IOException { - System.out.print(fetchVersionFromSite(args.length == 0 || args[0].equals("full"))); + System.out.print(fetchVersionFromSite(args.length < 2 || args[1].equals("full"), new Domain(args.length < 1 ? "" : args[0]))); } - public static String fetchVersionFromSite(boolean fetchFull) throws IOException { - InputStream in = new URL("https://projectlombok.org/download").openStream(); + public static String fetchVersionFromSite(boolean fetchFull, Domain domain) throws IOException { + InputStream in = domain.url("download").openStream(); try { BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); try { diff --git a/src/support/lombok/website/RunSite.java b/src/support/lombok/website/RunSite.java new file mode 100644 index 00000000..17e158c0 --- /dev/null +++ b/src/support/lombok/website/RunSite.java @@ -0,0 +1,103 @@ +package lombok.website; + +import static spark.Spark.*; + +import java.awt.Desktop; +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import spark.Request; +import spark.Response; +import spark.Route; + +public class RunSite { + private static final int DEFAULT_PORT = 4569; + private final Path base; + + public RunSite(Path base) { + this.base = base; + } + + public static void main(String[] args) throws Exception { + boolean open = args.length > 1 && args[1].equals("open"); + new RunSite(Paths.get(args[0])).go(open); + } + + private void go(boolean open) throws Exception { + port(DEFAULT_PORT); + get("/", serve("main.html")); + get("/setup/overview", serve("setup/main.html")); + get("/setup", serve("setup/main.html")); + get("/features", serve("features/index.html")); + get("/features/all", serve("features/index.html")); + get("/features/experimental/all", serve("features/experimental/index.html")); + get("/features/experimental", serve("features/experimental/index.html")); + + serveDir("/", base); + + System.out.println("Serving page from " + base + " -- hit enter to stop"); + if (open) Opener.open("http://localhost:" + DEFAULT_PORT + "/"); + System.in.read(); + System.exit(0); + } + + private void serveDir(String sub, Path dir) throws IOException { + DirectoryStream ds = Files.newDirectoryStream(dir); + try { + for (Path c : ds) { + String n = c.getFileName().toString(); + if (n.equals(".") || n.equals("..")) continue; + if (Files.isDirectory(c)) { + serveDir(sub + n + "/", c); + continue; + } + String rel = base.relativize(c).toString(); + get(sub + n, serve(rel)); + if (n.endsWith(".html")) get(sub + n.substring(0, n.length() - 5), serve(rel)); + } + } finally { + ds.close(); + } + } + + private static class Opener { + public static void open(String url) throws Exception { + Desktop.getDesktop().browse(new URI(url)); + } + } + + private Route serve(final String path) { + final Path tgt = base.resolve(path); + + return new Route() { + @Override public Object handle(Request req, Response res) throws Exception { + res.type(mapMime(path)); + return Files.readAllBytes(tgt); + } + }; + } + + private String mapMime(String path) { + if (path.endsWith(".css")) return "text/css; charset=UTF-8"; + if (path.endsWith(".js")) return "text/javascript; charset=UTF-8"; + if (path.endsWith(".png")) return "image/png"; + if (path.endsWith(".gif")) return "image/gif"; + if (path.endsWith(".jpg")) return "image/jpeg"; + if (path.endsWith(".mp4")) return "video/mp4"; + if (path.endsWith(".m4v")) return "video/mp4"; + if (path.endsWith(".ogv")) return "video/ogg"; + if (path.endsWith(".webm")) return "video/webm"; + if (path.endsWith(".ico")) return "image/x-icon"; + if (path.endsWith(".pdf")) return "application/pdf"; + if (path.endsWith(".json")) return "application/json"; + if (path.endsWith(".xml")) return "text/xml"; + if (path.endsWith(".woff")) return "font/woff"; + if (path.endsWith(".woff2")) return "font/woff2"; + if (path.endsWith(".html")) return "text/html; charset=UTF-8"; + return "text/plain; charset=UTF-8"; + } +} diff --git a/src/website/lombok/website/WebsiteMaker.java b/src/support/lombok/website/WebsiteMaker.java similarity index 82% rename from src/website/lombok/website/WebsiteMaker.java rename to src/support/lombok/website/WebsiteMaker.java index 87d6dcc6..d786e605 100644 --- a/src/website/lombok/website/WebsiteMaker.java +++ b/src/support/lombok/website/WebsiteMaker.java @@ -11,7 +11,6 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.reflect.Method; -import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -70,7 +69,14 @@ public class WebsiteMaker { } } - private static void buildAll(String version, String fullVersion, String argIn, String argOut) throws Exception { + private static void printAllVersions(Domain domain) throws Exception { + List> versions = readAllVersions(domain); + for (List v : versions) { + System.out.println(" " + v.get(1) + ""); + } + } + + private static void buildAll(Domain domain, String version, String fullVersion, String argIn, String argOut, boolean newRelease) throws Exception { File in, out; if (argIn == null) { in = new File("."); @@ -89,7 +95,7 @@ public class WebsiteMaker { out = new File(argOut); } WebsiteMaker maker = new WebsiteMaker(version, fullVersion, in, out); - maker.buildWebsite(); + maker.buildWebsite(domain, newRelease); } private static void buildChangelog(String version, String fullVersion, String argIn, String argOut) throws Exception { @@ -160,25 +166,32 @@ public class WebsiteMaker { public static void main(String[] args) throws Exception { String version, fullVersion; + Domain domain = new Domain(args.length < 1 ? "" : args[0]); - if (args.length < 2) { + if (args.length < 3) { version = VersionFinder.getVersion(); fullVersion = VersionFinder.getFullVersion(); } else { - version = args[0]; - fullVersion = args[1]; + version = args[1]; + fullVersion = args[2]; } - if (args.length < 3 || args[2].equalsIgnoreCase("all")) { - buildAll(version, fullVersion, args.length < 4 ? null : args[3], args.length < 5 ? null : args[4]); - } else if (args[2].equalsIgnoreCase("changelog")) { - buildChangelog(version, fullVersion, args.length < 4 ? null : args[3], args.length < 5 ? null : args[4]); - } else if (args[2].equalsIgnoreCase("download-edge")) { - buildDownloadEdge(version, fullVersion, args.length < 4 ? null : args[3], args.length < 5 ? null : args[4]); - } else if (args[2].equalsIgnoreCase("changelog-latest")) { - buildChangelogLatest(version, fullVersion, args.length < 4 ? null : args[3], args.length < 5 ? null : args[4]); + String argIn = args.length < 5 ? null : args[4]; + String argOut = args.length < 6 ? null : args[5]; + if (args.length < 4 || args[3].equalsIgnoreCase("all")) { + buildAll(domain, version, fullVersion, argIn, argOut, false); + } else if (args.length < 4 || args[3].equalsIgnoreCase("all-newrelease")) { + buildAll(domain, version, fullVersion, argIn, argOut, true); + } else if (args[3].equalsIgnoreCase("changelog")) { + buildChangelog(version, fullVersion, argIn, argOut); + } else if (args[3].equalsIgnoreCase("download-edge")) { + buildDownloadEdge(version, fullVersion, argIn, argOut); + } else if (args[3].equalsIgnoreCase("changelog-latest")) { + buildChangelogLatest(version, fullVersion, argIn, argOut); + } else if (args[3].equalsIgnoreCase("print-allversions")) { + printAllVersions(domain); } else { - throw new IllegalArgumentException("3rd argument must be one of 'all', 'changelog', 'download-edge', 'changelog-latest'"); + throw new IllegalArgumentException("4th argument must be one of 'all', 'changelog', 'download-edge', 'changelog-latest'"); } } @@ -230,11 +243,11 @@ public class WebsiteMaker { convertHtAccess(freemarkerConfig, out); } - public void buildWebsite() throws Exception { + public void buildWebsite(Domain domain, boolean newRelease) throws Exception { Configuration freemarkerConfig = makeFreemarkerConfig(); outputDir.mkdirs(); - convertTemplates(freemarkerConfig); + convertTemplates(domain, freemarkerConfig, newRelease); buildHtAccess(new File(outputDir, ".htaccess")); } @@ -298,10 +311,10 @@ public class WebsiteMaker { } } - private void convertTemplates(Configuration freemarker) throws Exception { + private void convertTemplates(Domain domain, Configuration freemarker, boolean newRelease) throws Exception { File basePagesLoc = new File(baseDir, "templates"); Map dataModel = createBasicDataModel(); - dataModel.putAll(createExtendedDataModel()); + dataModel.putAll(createExtendedDataModel(domain, newRelease)); convertTemplates_(freemarker, "", basePagesLoc, outputDir, 0, dataModel); } @@ -342,25 +355,39 @@ public class WebsiteMaker { } private static final Pattern LOMBOK_LINK = Pattern.compile("^.*([^<]+).*$"); - private Map createExtendedDataModel() throws IOException { + private Map createExtendedDataModel(Domain domain, boolean newRelease) throws IOException { Map data = new HashMap(); data.put("usages", new HtmlMaker(new File(baseDir, "usageExamples"))); - InputStream in = new URL("https://projectlombok.org/all-versions.html").openStream(); + List> allVersions = readAllVersions(domain); + if (!newRelease && !allVersions.isEmpty()) allVersions.remove(0); // remove current version; it will be 're-added' as current version automatically. + data.put("linksToVersions", allVersions); + + return data; + } + + private static List> readAllVersions(Domain domain) throws IOException { + InputStream in = domain.url("all-versions.html").openStream(); ArrayList> links = new ArrayList>(); try { BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); for (String line = br.readLine(); line != null; line = br.readLine()) { Matcher m = LOMBOK_LINK.matcher(line); - if (m.matches()) links.add(Arrays.asList(m.group(1), m.group(2))); + if (m.matches()) { + String url = m.group(1); + String name = m.group(2); + if (name.endsWith(" [Current Version]")) { + name = "lombok-" + name.substring(0, name.length() - " [Current Version]".length()) + ".jar"; + url = url.replace("lombok.jar", name); + } + links.add(Arrays.asList(name, url)); + } } } finally { in.close(); } - data.put("linksToVersions", links); - - return data; + return links; } public static class HtmlMaker { diff --git a/src/testAP/org/projectlombok/testAp/ExampleAnnotation.java b/src/testAP/org/projectlombok/testAp/ExampleAnnotation.java deleted file mode 100644 index b419326b..00000000 --- a/src/testAP/org/projectlombok/testAp/ExampleAnnotation.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.projectlombok.testAp; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.CLASS) -@Target(ElementType.TYPE) -public @interface ExampleAnnotation {} diff --git a/src/testAP/org/projectlombok/testAp/TestAp.java b/src/testAP/org/projectlombok/testAp/TestAp.java deleted file mode 100644 index b5f20d21..00000000 --- a/src/testAP/org/projectlombok/testAp/TestAp.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2016 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 org.projectlombok.testAp; - -import java.util.Set; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.TypeMirror; - -@SupportedAnnotationTypes("org.projectlombok.testAp.ExampleAnnotation") -public final class TestAp extends AbstractProcessor { - private int roundCounter = 0; - private static final long START = System.currentTimeMillis(); - - private void log(String txt) { - System.out.printf("***[%3d]: %s\n", System.currentTimeMillis() - START, txt); - } - - @Override public void init(ProcessingEnvironment processingEnv) { - log("TestAP in init"); - super.init(processingEnv); - } - - @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - roundCounter++; - log("TestAP in round " + roundCounter); - boolean foundGetTest = false; - int annotatedElemCount = 0; - for (Element annotated : roundEnv.getElementsAnnotatedWith(ExampleAnnotation.class)) { - annotatedElemCount++; - for (Element child : annotated.getEnclosedElements()) { - if (child.getSimpleName().toString().equals("getTest") && child.getKind() == ElementKind.METHOD) foundGetTest = true; - if (child instanceof ExecutableElement) { - TypeMirror returnType = ((ExecutableElement) child).getReturnType(); - System.out.println("RETURN TYPE for " + child.getSimpleName() + ": " + returnType.getClass() + " -- " + returnType.toString()); - } - } - } - - if (foundGetTest) log("RESULT: POSITIVE -- found the getTest method"); - else if (annotatedElemCount > 0) log("RESULT: NEGATIVE -- found the example class but there's no getTest method in it according to the type mirror."); - else log("RESULT: AMBIVALENT -- The example class is not provided by 'getElementsAnnotatedWith' in this round. Not an issue, unless previously you got a NEGATIVE result."); - - return false; - } - - @Override public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } -} diff --git a/src/useTestAP/UseTestAp.java b/src/useTestAP/UseTestAp.java deleted file mode 100644 index 2d7eab7b..00000000 --- a/src/useTestAP/UseTestAp.java +++ /dev/null @@ -1,13 +0,0 @@ -@org.projectlombok.testAp.ExampleAnnotation -//@lombok.experimental.Accessors(chain=true) -public class UseTestAp { - @lombok.Setter @lombok.Getter String test; - - public void confirmGetTestExists() { - System.out.println(getTest()); - } - - public UseTestAp returningSelf() { - return this; - } -} diff --git a/src/utils/lombok/core/JavaIdentifiers.java b/src/utils/lombok/core/JavaIdentifiers.java index cbe90eed..906ae0e1 100644 --- a/src/utils/lombok/core/JavaIdentifiers.java +++ b/src/utils/lombok/core/JavaIdentifiers.java @@ -21,6 +21,8 @@ */ package lombok.core; +import java.util.regex.Pattern; + /** * Utility functions for validating potential java verifiers. */ @@ -54,4 +56,13 @@ public class JavaIdentifiers { public static boolean isKeyword(String keyword) { return KEYWORDS.contains(keyword); } + + /** Matches any of the 8 primitive names, such as {@code boolean}. */ + private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(?:boolean|byte|short|int|long|float|double|char)$"); + + public static boolean isPrimitive(String typeName) { + return PRIMITIVE_TYPE_NAME_PATTERN.matcher(typeName).matches(); + } + + } diff --git a/src/utils/lombok/core/SpiLoadUtil.java b/src/utils/lombok/core/SpiLoadUtil.java index e685acd6..0feb7f12 100644 --- a/src/utils/lombok/core/SpiLoadUtil.java +++ b/src/utils/lombok/core/SpiLoadUtil.java @@ -129,9 +129,10 @@ public class SpiLoadUtil { private static void readServicesFromUrl(Collection list, URL url) throws IOException { InputStream in = url.openStream(); + BufferedReader r = null; try { if (in == null) return; - BufferedReader r = new BufferedReader(new InputStreamReader(in, "UTF-8")); + r = new BufferedReader(new InputStreamReader(in, "UTF-8")); while (true) { String line = r.readLine(); if (line == null) break; @@ -143,6 +144,7 @@ public class SpiLoadUtil { } } finally { try { + if (r != null) r.close(); if (in != null) in.close(); } catch (Throwable ignore) {} } diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index 31f2518a..31979955 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -29,6 +29,7 @@ import java.util.regex.Pattern; import lombok.core.ClassLiteral; import lombok.core.FieldSelect; +import lombok.core.JavaIdentifiers; import lombok.permit.Permit; import org.eclipse.jdt.internal.compiler.ast.ASTNode; @@ -158,16 +159,12 @@ public class Eclipse { return result.toArray(EMPTY_ANNOTATIONS_ARRAY); } - /** Matches any of the 8 primitive names, such as {@code boolean}. */ - private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile( - "^(boolean|byte|short|int|long|float|double|char)$"); - /** * Checks if the given type reference represents a primitive type. */ public static boolean isPrimitive(TypeReference ref) { if (ref.dimensions() > 0) return false; - return PRIMITIVE_TYPE_NAME_PATTERN.matcher(toQualifiedName(ref.getTypeName())).matches(); + return JavaIdentifiers.isPrimitive(toQualifiedName(ref.getTypeName())); } /** diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index 3cc72f4e..cec43705 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -37,12 +37,6 @@ 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; -import lombok.permit.Permit; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Symtab; @@ -61,6 +55,13 @@ import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import lombok.core.ClassLiteral; +import lombok.core.FieldSelect; +import lombok.core.JavaIdentifiers; +import lombok.javac.JavacTreeMaker.TreeTag; +import lombok.javac.JavacTreeMaker.TypeTag; +import lombok.permit.Permit; + /** * Container for static utility methods relevant to lombok's operation on javac. */ @@ -69,9 +70,6 @@ public class Javac { // prevent instantiation } - /** Matches any of the 8 primitive names, such as {@code boolean}. */ - private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$"); - private static final Pattern VERSION_PARSER = Pattern.compile("^(\\d{1,6})\\.?(\\d{1,6})?.*$"); private static final Pattern SOURCE_PARSER = Pattern.compile("^JDK(\\d{1,6})_?(\\d{1,6})?.*$"); @@ -135,8 +133,7 @@ public class Javac { * expression) represents a primitive type. */ public static boolean isPrimitive(JCExpression ref) { - String typeName = ref.toString(); - return PRIMITIVE_TYPE_NAME_PATTERN.matcher(typeName).matches(); + return JavaIdentifiers.isPrimitive(ref.toString()); } /** diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java index 20f4b66d..15a11151 100644 --- a/src/utils/lombok/javac/JavacTreeMaker.java +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -343,10 +343,7 @@ public class JavacTreeMaker { Method method = getFromCache(m); try { if (m.returnType.isPrimitive()) { - Object res = method.invoke(owner, args); - String sn = res.getClass().getSimpleName().toLowerCase(); - if (!sn.startsWith(m.returnType.getSimpleName())) throw new ClassCastException(res.getClass() + " to " + m.returnType); - return (J) res; + return (J) method.invoke(owner, args); } return m.returnType.cast(method.invoke(owner, args)); } catch (InvocationTargetException e) { diff --git a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java index 08477e61..d7b1d569 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java +++ b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2019 The Project Lombok Authors. + * Copyright (C) 2013-2020 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 @@ -59,7 +59,7 @@ class CommentCollectingTokenizer extends JavaTokenizer { @Override public Token readToken() { Token token = super.readToken(); prevEndPosition = pos(); - if (textBlockStarts != null && (prevEndPosition - token.pos > 5) && token.getClass().getSimpleName().equals("StringToken")) { + if (textBlockStarts != null && (prevEndPosition - token.pos > 5) && token.getClass().getName().endsWith("$StringToken")) { char[] start = reader.getRawCharacters(token.pos, token.pos + 3); if (start[0] == '"' && start[1] == '"' && start[2] == '"') textBlockStarts.add(token.pos); } diff --git a/src/utils/lombok/permit/Permit.java b/src/utils/lombok/permit/Permit.java index b7c5f0d9..407c3922 100644 --- a/src/utils/lombok/permit/Permit.java +++ b/src/utils/lombok/permit/Permit.java @@ -95,6 +95,7 @@ public class Permit { static class Fake { boolean override; + Object accessCheckCache; } public static Method getMethod(Class c, String mName, Class... parameterTypes) throws NoSuchMethodException { diff --git a/ssh.knownHosts b/ssh.knownHosts index 873e852f..6cce7f01 100644 --- a/ssh.knownHosts +++ b/ssh.knownHosts @@ -1,2 +1,2 @@ projectlombok.org:22:ECDSA:X.509:MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wRAQg/////wAAAAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQawzFOw9jvOPD4n0mBLBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABKwMbAFQuRwz9+PnuBOlc1OqPAYVhg0VBTGQ1G5V6JVfb0CU5GH4NEFp+jEAoGCZNrghB0XLB3d3egfF06ihDgE= - +projectlombok.org:22:EdDSA:X.509:MCowBQYDK2VwAyEA450nCMycc70u7i0qetTrh9yl6+cOS6v4y8clPCnSIHs= diff --git a/test/configuration/src/lombok/core/configuration/TestConfiguration.java b/test/configuration/src/lombok/core/configuration/TestConfiguration.java index 3032daf3..504c36b2 100644 --- a/test/configuration/src/lombok/core/configuration/TestConfiguration.java +++ b/test/configuration/src/lombok/core/configuration/TestConfiguration.java @@ -65,8 +65,8 @@ public class TestConfiguration { outStream.flush(); errStream.flush(); - String out = new String(rawOut.toByteArray()).replace("\r\n", "\n").replace('\\', '/').replaceAll(Pattern.quote(normalizedName) + "|" + Pattern.quote(baseName), "BASE/").trim(); - String err = new String(rawErr.toByteArray()).replace("\r\n", "\n").replace('\\', '/').replaceAll(Pattern.quote(normalizedName) + "|" + Pattern.quote(baseName), "BASE/").trim(); + String out = new String(rawOut.toByteArray()).replace('\\', '/').replaceAll(Pattern.quote(normalizedName) + "|" + Pattern.quote(baseName), "BASE/").trim(); + String err = new String(rawErr.toByteArray()).replace('\\', '/').replaceAll(Pattern.quote(normalizedName) + "|" + Pattern.quote(baseName), "BASE/").trim(); checkContent(directory, out, "out"); checkContent(directory, err, "err"); diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index d223ae03..448f77ab 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -91,7 +91,7 @@ public abstract class AbstractRunTests { } }); - boolean changed = transformCode(messages, writer, file, sourceDirectives_.getSpecifiedEncoding(), sourceDirectives_.getFormatPreferences()); + boolean changed = transformCode(messages, writer, file, sourceDirectives_.getSpecifiedEncoding(), sourceDirectives_.getFormatPreferences(), sourceDirectives_.minVersion()); boolean forceUnchanged = sourceDirectives_.forceUnchanged() || sourceDirectives_.isSkipCompareContent(); if (params.expectChanges() && !forceUnchanged && !changed) messages.add(new CompilerMessage(-1, -1, true, "not flagged modified")); if (!params.expectChanges() && changed) messages.add(new CompilerMessage(-1, -1, true, "unexpected modification")); @@ -101,7 +101,7 @@ public abstract class AbstractRunTests { }; } - protected abstract boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences) throws Throwable; + protected abstract boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences, int minVersion) throws Throwable; protected String readFile(File file) throws IOException { BufferedReader reader; @@ -190,6 +190,8 @@ public abstract class AbstractRunTests { for (CompilerMessage actualMessage : actualMessages) { System.out.println(actualMessage); } + System.out.println("**** Actual File ******"); + System.out.println(lineNumber(actualFile)); System.out.println("*******************"); } if (dumpActualFilesHere != null) { @@ -199,6 +201,22 @@ public abstract class AbstractRunTests { } } + private CharSequence lineNumber(String content) { + StringBuilder out = new StringBuilder(); + int pos = 0; + int ln = 1; + while (true) { + out.append(String.format("%4d ", ln)); + int idx = content.indexOf('\n', pos); + if (idx == -1) { + return out.append(content.substring(pos)); + } + out.append(content.substring(pos, idx + 1)); + ln++; + pos = idx + 1; + } + } + @SuppressWarnings("null") /* eclipse bug workaround; it falsely thinks stuffAc will always be null. */ private static void compareMessages(String name, LombokImmutableList expected, LinkedHashSet actual) { Iterator expectedIterator = expected.iterator(); @@ -267,7 +285,7 @@ public abstract class AbstractRunTests { endIdx--; } - return in.substring(0, endIdx); + return in.substring(0, endIdx + 1); } private static String[] removeBlanks(String[] in) { diff --git a/test/core/src/lombok/DirectoryRunner.java b/test/core/src/lombok/DirectoryRunner.java index b8b1da43..a174355d 100644 --- a/test/core/src/lombok/DirectoryRunner.java +++ b/test/core/src/lombok/DirectoryRunner.java @@ -47,7 +47,7 @@ public class DirectoryRunner extends Runner { @Override public int getVersion() { return Javac.getJavaCompilerVersion(); } - }, + }, JAVAC { @Override public int getVersion() { return DELOMBOK.getVersion(); @@ -82,8 +82,22 @@ public class DirectoryRunner extends Runner { private static final FileFilter JAVA_FILE_FILTER = new FileFilter() { @Override public boolean accept(File file) { - return file.isFile() && file.getName().endsWith(".java") && - (DEBUG_FOCUS_ON_FILE.isEmpty() || DEBUG_FOCUS_ON_FILE.contains(file.getName())); + if (!file.isFile() || !file.getName().endsWith(".java")) return false; + boolean positiveFilter = false; + for (String dfof : DEBUG_FOCUS_ON_FILE) { + if (dfof.isEmpty()) continue; + if (!dfof.endsWith(".java")) dfof = dfof + ".java"; + boolean invert = dfof.startsWith("!"); + if (invert) dfof = dfof.substring(1); + positiveFilter = positiveFilter || !invert; + int starIdx = dfof.indexOf('*'); + if (starIdx == -1) { + if (file.getName().equals(dfof)) return !invert; + } else { + if (file.getName().startsWith(dfof.substring(0, starIdx)) && file.getName().endsWith(dfof.substring(starIdx + 1))) return !invert; + } + } + return !positiveFilter; } }; diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index b04f0ba0..57a32333 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -358,4 +358,8 @@ public class LombokTestSource { if (specifiedEncoding == null || specifiedEncoding.equalsIgnoreCase(encoding)) return source; return read0(sourceFolder, messagesFolder, fileName, specifiedEncoding); } + + public int minVersion() { + return Math.max(6, versionLowerLimit); + } } diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java index 0887de32..ffac8372 100644 --- a/test/core/src/lombok/RunTestsViaDelombok.java +++ b/test/core/src/lombok/RunTestsViaDelombok.java @@ -38,7 +38,7 @@ public class RunTestsViaDelombok extends AbstractRunTests { private Delombok delombok = new Delombok(); @Override - public boolean transformCode(Collection messages, StringWriter result, final File file, String encoding, Map formatPreferences) throws Throwable { + public boolean transformCode(Collection messages, StringWriter result, final File file, String encoding, Map formatPreferences, int version) throws Throwable { delombok.setVerbose(true); ChangedChecker cc = new ChangedChecker(); delombok.setFeedback(cc.feedback); diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index 3efe38f5..739d6316 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 The Project Lombok Authors. + * Copyright (C) 2010-2020 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 @@ -23,25 +23,33 @@ package lombok; import java.io.File; import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; +import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import lombok.eclipse.Eclipse; import lombok.javac.CapturingDiagnosticListener.CompilerMessage; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.ICompilerRequestor; import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; import org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; @@ -69,7 +77,8 @@ public class RunTestsViaEcj extends AbstractRunTests { warnings.put(CompilerOptions.OPTION_ReportUnusedLabel, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedImport, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, "ignore"); - warnings.put(CompilerOptions.OPTION_Source, "1." + Eclipse.getEcjCompilerVersion()); + int ecjVersion = Eclipse.getEcjCompilerVersion(); + warnings.put(CompilerOptions.OPTION_Source, (ecjVersion < 9 ? "1." : "") + ecjVersion); options.set(warnings); return options; } @@ -92,7 +101,7 @@ public class RunTestsViaEcj extends AbstractRunTests { } @Override - public boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences) throws Throwable { + public boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences, int minVersion) throws Throwable { final AtomicReference compilationResult_ = new AtomicReference(); final AtomicReference compilationUnit_ = new AtomicReference(); ICompilerRequestor bitbucketRequestor = new ICompilerRequestor() { @@ -102,9 +111,10 @@ public class RunTestsViaEcj extends AbstractRunTests { }; String source = readFile(file); - final CompilationUnit sourceUnit = new CompilationUnit(source.toCharArray(), file.getName(), encoding == null ? "UTF-8" : encoding); + char[] sourceArray = source.toCharArray(); + final org.eclipse.jdt.internal.compiler.batch.CompilationUnit sourceUnit = new org.eclipse.jdt.internal.compiler.batch.CompilationUnit(sourceArray, file.getName(), encoding == null ? "UTF-8" : encoding); - Compiler ecjCompiler = new Compiler(createFileSystem(file), ecjErrorHandlingPolicy(), ecjCompilerOptions(), bitbucketRequestor, new DefaultProblemFactory(Locale.ENGLISH)) { + Compiler ecjCompiler = new Compiler(createFileSystem(file, minVersion), ecjErrorHandlingPolicy(), ecjCompilerOptions(), bitbucketRequestor, new DefaultProblemFactory(Locale.ENGLISH)) { @Override protected synchronized void addCompilationUnit(ICompilationUnit inUnit, CompilationUnitDeclaration parsedUnit) { if (inUnit == sourceUnit) compilationUnit_.set(parsedUnit); super.addCompilationUnit(inUnit, parsedUnit); @@ -125,10 +135,76 @@ public class RunTestsViaEcj extends AbstractRunTests { if (cud == null) result.append("---- No CompilationUnit provided by ecj ----"); else result.append(cud.toString()); + if (eclipseAvailable()) { + EclipseDomConversion.toDomAst(cud, sourceArray); + } + return true; } - private FileSystem createFileSystem(File file) { + private boolean eclipseAvailable() { + try { + Class.forName("org.eclipse.jdt.core.dom.CompilationUnit"); + } catch (Throwable t) { + return false; + } + + return true; + } + + private static final String bootRuntimePath = System.getProperty("delombok.bootclasspath"); + + private static class EclipseDomConversion { + static CompilationUnit toDomAst(CompilationUnitDeclaration cud, final char[] source) { + Map options = new HashMap(); + options.put(JavaCore.COMPILER_SOURCE, "11"); + options.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled"); + try { + org.eclipse.jdt.internal.core.CompilationUnit ccu = new org.eclipse.jdt.internal.core.CompilationUnit(null, null, null) { + @Override public char[] getContents() { + return source; + } + }; + return AST.convertCompilationUnit(4, cud, options, false, ccu, 0, null); + } catch (SecurityException e) { + try { + debugClasspathConflicts("org/eclipse/jdt/internal/compiler"); + } catch (Exception e2) { + throw Lombok.sneakyThrow(e2); + } + throw e; + } + } + } + + @SuppressWarnings({"all"}) + private static void debugClasspathConflicts(String prefixToLookFor) throws Exception { + String[] paths = System.getProperty("java.class.path").split(":"); + for (String p : paths) { + Path cp = Paths.get(p); + if (Files.isDirectory(cp)) { + if (Files.isDirectory(cp.resolve(prefixToLookFor))) System.out.println("** DIR-BASED: " + cp); + } else if (Files.isRegularFile(cp)) { + JarFile jf = new JarFile(cp.toFile()); + try { + Enumeration jes = jf.entries(); + while (jes.hasMoreElements()) { + JarEntry je = jes.nextElement(); + if (je.getName().startsWith(prefixToLookFor)) { + System.out.println("** JAR-BASED: " + cp); + break; + } + } + } finally { + jf.close(); + } + } else { + System.out.println("** MISSING: " + cp); + } + } + } + + private FileSystem createFileSystem(File file, int minVersion) { List classpath = new ArrayList(); for (Iterator i = classpath.iterator(); i.hasNext();) { if (FileSystem.getClasspath(i.next(), "UTF-8", null) == null) { @@ -137,16 +213,14 @@ public class RunTestsViaEcj extends AbstractRunTests { } if (new File("bin").exists()) classpath.add("bin"); classpath.add("dist/lombok.jar"); - classpath.add("lib/oracleJDK8Environment/rt.jar"); - classpath.add("lib/test/commons-logging-commons-logging.jar"); - classpath.add("lib/test/org.slf4j-slf4j-api.jar"); - classpath.add("lib/test/org.slf4j-slf4j-ext.jar"); - classpath.add("lib/test/log4j-log4j.jar"); - classpath.add("lib/test/org.apache.logging.log4j-log4j-api.jar"); - 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"); + if (bootRuntimePath == null || bootRuntimePath.isEmpty()) throw new IllegalStateException("System property delombok.bootclasspath is not set; set it to the rt of java6 or java8"); + classpath.add(bootRuntimePath); + for (File f : new File("lib/test").listFiles()) { + String fn = f.getName(); + if (fn.length() < 4) continue; + if (!fn.substring(fn.length() - 4).toLowerCase().equals(".jar")) continue; + classpath.add("lib/test/" + fn); + } return new FileSystem(classpath.toArray(new String[0]), new String[] {file.getAbsolutePath()}, "UTF-8"); } } diff --git a/test/transform/src/lombok/transform/RunTransformTests.java b/test/core/src/lombok/TestBase.java similarity index 84% rename from test/transform/src/lombok/transform/RunTransformTests.java rename to test/core/src/lombok/TestBase.java index 0afbc5d6..4b0c02f3 100644 --- a/test/transform/src/lombok/transform/RunTransformTests.java +++ b/test/core/src/lombok/TestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 The Project Lombok Authors. + * Copyright (C) 2011-2020 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 @@ -19,13 +19,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package lombok.transform; +package lombok; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({TestLombokFilesIdempotent.class, TestSourceFiles.class, TestWithDelombok.class, TestWithEcj.class}) -public class RunTransformTests { +@SuiteClasses({lombok.core.configuration.RunConfigurationTests.class, lombok.core.RunCoreTests.class}) +public class TestBase { } diff --git a/test/core/src/lombok/RunAllTests.java b/test/core/src/lombok/TestEclipse.java similarity index 82% rename from test/core/src/lombok/RunAllTests.java rename to test/core/src/lombok/TestEclipse.java index 1ca76af5..9fe798bc 100644 --- a/test/core/src/lombok/RunAllTests.java +++ b/test/core/src/lombok/TestEclipse.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 The Project Lombok Authors. + * Copyright (C) 2011-2020 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,6 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({lombok.transform.RunTransformTests.class, lombok.bytecode.RunBytecodeTests.class, lombok.core.configuration.RunConfigurationTests.class, lombok.core.RunCoreTests.class}) -public class RunAllTests { +@SuiteClasses({lombok.transform.TestWithEcj.class}) +public class TestEclipse { } diff --git a/test/core/src/lombok/TestJavac.java b/test/core/src/lombok/TestJavac.java new file mode 100644 index 00000000..fbc495ad --- /dev/null +++ b/test/core/src/lombok/TestJavac.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011-2020 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({lombok.bytecode.RunBytecodeTests.class, lombok.transform.TestLombokFilesIdempotent.class, lombok.transform.TestSourceFiles.class, lombok.transform.TestWithDelombok.class}) +public class TestJavac { +} diff --git a/test/pretty/resource/after/ThisParameter.java b/test/pretty/resource/after/ThisParameter.java new file mode 100644 index 00000000..49452a59 --- /dev/null +++ b/test/pretty/resource/after/ThisParameter.java @@ -0,0 +1,34 @@ +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +class ThisParameter { + void untagged(ThisParameter this, int i) { + // no content + } + void sourceTagged(@SourceTagged("source") ThisParameter this) { + // no content + } + void classTagged(@ClassTagged("class") ThisParameter this) { + // no content + } + void runtimeTagged(@RuntimeTagged("runtime") ThisParameter this) { + // no content + } + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.SOURCE) + @interface SourceTagged { + String value(); + } + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.CLASS) + @interface ClassTagged { + String value(); + } + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.RUNTIME) + @interface RuntimeTagged { + String value(); + } +} diff --git a/test/pretty/resource/before/ThisParameter.java b/test/pretty/resource/before/ThisParameter.java new file mode 100644 index 00000000..d95c0261 --- /dev/null +++ b/test/pretty/resource/before/ThisParameter.java @@ -0,0 +1,41 @@ +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +class ThisParameter { + + void untagged(ThisParameter this, int i) { + // no content + } + + void sourceTagged(@SourceTagged("source") ThisParameter this) { + // no content + } + + void classTagged(@ClassTagged("class") ThisParameter this) { + // no content + } + + void runtimeTagged(@RuntimeTagged("runtime") ThisParameter this) { + // no content + } + + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.SOURCE) + @interface SourceTagged { + String value(); + } + + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.CLASS) + @interface ClassTagged { + String value(); + } + + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.RUNTIME) + @interface RuntimeTagged { + String value(); + } +} diff --git a/test/stubs/com/fasterxml/jackson/annotation/JsonAnySetter.java b/test/stubs/com/fasterxml/jackson/annotation/JsonAnySetter.java new file mode 100644 index 00000000..51d2c3fa --- /dev/null +++ b/test/stubs/com/fasterxml/jackson/annotation/JsonAnySetter.java @@ -0,0 +1,12 @@ +package com.fasterxml.jackson.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JsonAnySetter { + boolean enabled() default true; +} diff --git a/test/transform/resource/after-delombok/BuilderConstructorJavadoc.java b/test/transform/resource/after-delombok/BuilderConstructorJavadoc.java new file mode 100644 index 00000000..96673b1a --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderConstructorJavadoc.java @@ -0,0 +1,85 @@ +import java.util.List; + +class BuilderConstructorJavadoc { + /** + * This is a comment + * + * @param basic tag is moved to the setter + * @param multiline a param comment + * can be on multiple lines and can use + * {@code @code} or tags + * @param predef don't copy this one + * @param predefWithJavadoc don't copy this one + */ + BuilderConstructorJavadoc(int basic, int multiline, int predef, int predefWithJavadoc) { + } + + + public static class BuilderConstructorJavadocBuilder { + @java.lang.SuppressWarnings("all") + private int basic; + @java.lang.SuppressWarnings("all") + private int multiline; + @java.lang.SuppressWarnings("all") + private int predef; + @java.lang.SuppressWarnings("all") + private int predefWithJavadoc; + + public BuilderConstructorJavadocBuilder predef(final int x) { + this.predef = x; + return this; + } + + /** + * This javadoc remains untouched. + * @param x 1/100 of the thing + * @return the updated builder + */ + public BuilderConstructorJavadocBuilder predefWithJavadoc(final int x) { + this.predefWithJavadoc = x; + return this; + } + + @java.lang.SuppressWarnings("all") + BuilderConstructorJavadocBuilder() { + } + + /** + * @param basic tag is moved to the setter + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder basic(final int basic) { + this.basic = basic; + return this; + } + + /** + * @param multiline a param comment + * can be on multiple lines and can use + * {@code @code} or tags + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder multiline(final int multiline) { + this.multiline = multiline; + return this; + } + + @java.lang.SuppressWarnings("all") + public BuilderConstructorJavadoc build() { + return new BuilderConstructorJavadoc(this.basic, this.multiline, this.predef, this.predefWithJavadoc); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder(basic=" + this.basic + ", multiline=" + this.multiline + ", predef=" + this.predef + ", predefWithJavadoc=" + this.predefWithJavadoc + ")"; + } + } + + @java.lang.SuppressWarnings("all") + public static BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder builder() { + return new BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/BuilderDefaults.java b/test/transform/resource/after-delombok/BuilderDefaults.java index 5a563024..42b751ce 100644 --- a/test/transform/resource/after-delombok/BuilderDefaults.java +++ b/test/transform/resource/after-delombok/BuilderDefaults.java @@ -85,10 +85,10 @@ public final class BuilderDefaults { if (!(o instanceof BuilderDefaults)) return false; final BuilderDefaults other = (BuilderDefaults) o; if (this.getX() != other.getX()) return false; + if (this.getZ() != other.getZ()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; - if (this.getZ() != other.getZ()) return false; return true; } @java.lang.Override @@ -97,10 +97,10 @@ public final class BuilderDefaults { final int PRIME = 59; int result = 1; result = result * PRIME + this.getX(); - final java.lang.Object $name = this.getName(); - result = result * PRIME + ($name == null ? 43 : $name.hashCode()); final long $z = this.getZ(); result = result * PRIME + (int) ($z >>> 32 ^ $z); + final java.lang.Object $name = this.getName(); + result = result * PRIME + ($name == null ? 43 : $name.hashCode()); return result; } @java.lang.Override @@ -108,4 +108,4 @@ public final class BuilderDefaults { public java.lang.String toString() { return "BuilderDefaults(x=" + this.getX() + ", name=" + this.getName() + ", z=" + this.getZ() + ")"; } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java b/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java index 0f7f8997..30408c3b 100644 --- a/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java +++ b/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java @@ -124,7 +124,7 @@ class CheckerFrameworkSuperBuilder { return new CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl(); } } - public static class Child extends Parent { + public static class ZChild extends Parent { int a; int b; @java.lang.SuppressWarnings("all") @@ -132,7 +132,7 @@ class CheckerFrameworkSuperBuilder { return 1; } @java.lang.SuppressWarnings("all") - public static abstract class ChildBuilder> extends Parent.ParentBuilder { + public static abstract class ZChildBuilder> extends Parent.ParentBuilder { @java.lang.SuppressWarnings("all") private boolean a$set; @java.lang.SuppressWarnings("all") @@ -147,17 +147,17 @@ class CheckerFrameworkSuperBuilder { @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.Override @java.lang.SuppressWarnings("all") - public abstract C build(@org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.Child this); + public abstract C build(@org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild this); @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") - public B a(@org.checkerframework.checker.builder.qual.NotCalledMethods("a") CheckerFrameworkSuperBuilder.Child.ChildBuilder this, final int a) { + public B a(@org.checkerframework.checker.builder.qual.NotCalledMethods("a") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this, final int a) { this.a$value = a; a$set = true; return self(); } @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") - public B b(@org.checkerframework.checker.builder.qual.NotCalledMethods("b") CheckerFrameworkSuperBuilder.Child.ChildBuilder this, final int b) { + public B b(@org.checkerframework.checker.builder.qual.NotCalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this, final int b) { this.b = b; return self(); } @@ -165,41 +165,41 @@ class CheckerFrameworkSuperBuilder { @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { - return "CheckerFrameworkSuperBuilder.Child.ChildBuilder(super=" + super.toString() + ", a$value=" + this.a$value + ", b=" + this.b + ")"; + return "CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder(super=" + super.toString() + ", a$value=" + this.a$value + ", b=" + this.b + ")"; } } @java.lang.SuppressWarnings("all") - private static final class ChildBuilderImpl extends CheckerFrameworkSuperBuilder.Child.ChildBuilder { + private static final class ZChildBuilderImpl extends CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder { @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") - private ChildBuilderImpl() { + private ZChildBuilderImpl() { } @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") - protected CheckerFrameworkSuperBuilder.Child.ChildBuilderImpl self() { + protected CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { return this; } @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.Override @java.lang.SuppressWarnings("all") - public CheckerFrameworkSuperBuilder.Child build(@org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.Child.ChildBuilderImpl this) { - return new CheckerFrameworkSuperBuilder.Child(this); + public CheckerFrameworkSuperBuilder.ZChild build(@org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl this) { + return new CheckerFrameworkSuperBuilder.ZChild(this); } } @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") - protected Child(final CheckerFrameworkSuperBuilder.Child.ChildBuilder b) { + protected ZChild(final CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder b) { super(b); if (b.a$set) this.a = b.a$value; - else this.a = CheckerFrameworkSuperBuilder.Child.$default$a(); + else this.a = CheckerFrameworkSuperBuilder.ZChild.$default$a(); this.b = b.b; } @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") - public static CheckerFrameworkSuperBuilder.Child.ChildBuilder builder() { - return new CheckerFrameworkSuperBuilder.Child.ChildBuilderImpl(); + public static CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder builder() { + return new CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl(); } } } \ No newline at end of file diff --git a/test/transform/resource/after-delombok/DelegateAlreadyImplemented.java b/test/transform/resource/after-delombok/DelegateAlreadyImplemented.java new file mode 100644 index 00000000..c876d8ce --- /dev/null +++ b/test/transform/resource/after-delombok/DelegateAlreadyImplemented.java @@ -0,0 +1,43 @@ +public class DelegateAlreadyImplemented { + private A a; + + public void a() { + } + + public void b(java.util.List l) { + } + + public void c(java.util.List l, String[] a, Integer... varargs) { + } + + public void d(String[][][][] d) { + } + + public void e(Y x) { + } + + @SuppressWarnings("unchecked") + public void f(T s, java.util.List l, T[] a, T... varargs) { + } + + public void g(Number g) { + } +} + +interface A { + void a(); + + void b(java.util.List l); + + @SuppressWarnings("unchecked") + void c(java.util.List l, String[] a, T... varargs); + + void d(String[][][][] d); + + X e(X x); + + @SuppressWarnings("unchecked") + void f(T2 s, java.util.List l, T2[] a, T2... varargs); + + void g(G g); +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/DelegateGenerics.java b/test/transform/resource/after-delombok/DelegateGenerics.java new file mode 100644 index 00000000..894776ea --- /dev/null +++ b/test/transform/resource/after-delombok/DelegateGenerics.java @@ -0,0 +1,32 @@ +public class DelegateGenerics { + I1 target; + + @java.lang.SuppressWarnings("all") + public java.lang.Integer t(final java.lang.Integer t) { + return this.target.t(t); + } + + @java.lang.SuppressWarnings("all") + public java.lang.String i(final java.lang.String a) { + return this.target.i(a); + } + + @java.lang.SuppressWarnings("all") + public T a(final T a) { + return this.target.a(a); + } +} + +interface I1 extends I2 { +} + +interface I2 extends I3 { +} + +interface I3 { + T t(T t); + + I i(I a); + + A a(A a); +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/DelegateWithVarargs2.java b/test/transform/resource/after-delombok/DelegateWithVarargs2.java new file mode 100644 index 00000000..a8ff6e3b --- /dev/null +++ b/test/transform/resource/after-delombok/DelegateWithVarargs2.java @@ -0,0 +1,12 @@ +class DelegateWithVarargs2 { + private DelegateWithVarargs2.B bar; + public class B { + public void varargs(Object[]... keys) { + } + } + @java.lang.SuppressWarnings("all") + public void varargs(final java.lang.Object[]... keys) { + this.bar.varargs(keys); + } +} + diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeRank.java b/test/transform/resource/after-delombok/EqualsAndHashCodeRank.java new file mode 100644 index 00000000..fcf371b6 --- /dev/null +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeRank.java @@ -0,0 +1,31 @@ +public class EqualsAndHashCodeRank { + int a; + int b; + int c; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCodeRank)) return false; + final EqualsAndHashCodeRank other = (EqualsAndHashCodeRank) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.a != other.a) return false; + if (this.c != other.c) return false; + if (this.b != other.b) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof EqualsAndHashCodeRank; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.a; + result = result * PRIME + this.c; + result = result * PRIME + this.b; + return result; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/GetterLazyArguments.java b/test/transform/resource/after-delombok/GetterLazyArguments.java new file mode 100644 index 00000000..a8a422c0 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterLazyArguments.java @@ -0,0 +1,101 @@ +class GetterLazyArguments { + static String fun() { + return null; + } + + static String stringInt(String arg1, Integer arg2) { + return null; + } + + static String stringRunnable(String arg1, Runnable arg2) { + return null; + } + + private final java.util.concurrent.atomic.AtomicReference field1 = new java.util.concurrent.atomic.AtomicReference(); + private final java.util.concurrent.atomic.AtomicReference field2 = new java.util.concurrent.atomic.AtomicReference(); + private final java.util.concurrent.atomic.AtomicReference field3 = new java.util.concurrent.atomic.AtomicReference(); + private final java.util.concurrent.atomic.AtomicReference field4 = new java.util.concurrent.atomic.AtomicReference(); + private final java.util.concurrent.atomic.AtomicReference field5 = new java.util.concurrent.atomic.AtomicReference(); + + @java.lang.SuppressWarnings({"all", "unchecked"}) + public String getField1() { + java.lang.Object value = this.field1.get(); + if (value == null) { + synchronized (this.field1) { + value = this.field1.get(); + if (value == null) { + final String actualValue = stringInt(("a"), (1)); + value = actualValue == null ? this.field1 : actualValue; + this.field1.set(value); + } + } + } + return (String) (value == this.field1 ? null : value); + } + + @java.lang.SuppressWarnings({"all", "unchecked"}) + public String getField2() { + java.lang.Object value = this.field2.get(); + if (value == null) { + synchronized (this.field2) { + value = this.field2.get(); + if (value == null) { + final String actualValue = stringInt(true ? "a" : "b", true ? 1 : 0); + value = actualValue == null ? this.field2 : actualValue; + this.field2.set(value); + } + } + } + return (String) (value == this.field2 ? null : value); + } + + @java.lang.SuppressWarnings({"all", "unchecked"}) + public String getField3() { + java.lang.Object value = this.field3.get(); + if (value == null) { + synchronized (this.field3) { + value = this.field3.get(); + if (value == null) { + final String actualValue = stringInt(("a"), true ? 1 : 0); + value = actualValue == null ? this.field3 : actualValue; + this.field3.set(value); + } + } + } + return (String) (value == this.field3 ? null : value); + } + + @java.lang.SuppressWarnings({"all", "unchecked"}) + public String getField4() { + java.lang.Object value = this.field4.get(); + if (value == null) { + synchronized (this.field4) { + value = this.field4.get(); + if (value == null) { + final String actualValue = stringRunnable(fun(), () -> { + }); + value = actualValue == null ? this.field4 : actualValue; + this.field4.set(value); + } + } + } + return (String) (value == this.field4 ? null : value); + } + + @java.lang.SuppressWarnings({"all", "unchecked"}) + public String getField5() { + java.lang.Object value = this.field5.get(); + if (value == null) { + synchronized (this.field5) { + value = this.field5.get(); + if (value == null) { + final String actualValue = stringRunnable(("a"), () -> { + }); + value = actualValue == null ? this.field5 : actualValue; + this.field5.set(value); + } + } + } + return (String) (value == this.field5 ? null : value); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/GetterSetterJavadoc.java b/test/transform/resource/after-delombok/GetterSetterJavadoc.java index ae662da7..78d120a4 100644 --- a/test/transform/resource/after-delombok/GetterSetterJavadoc.java +++ b/test/transform/resource/after-delombok/GetterSetterJavadoc.java @@ -115,7 +115,7 @@ class GetterSetterJavadoc4 { /** * Some text * - * @param fieldName Hello, World5 + * @param fieldName Hello, World4 * @return {@code this}. */ @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-delombok/JacksonBuilderSingular.java b/test/transform/resource/after-delombok/JacksonBuilderSingular.java new file mode 100644 index 00000000..feaa6832 --- /dev/null +++ b/test/transform/resource/after-delombok/JacksonBuilderSingular.java @@ -0,0 +1,177 @@ +import java.util.List; +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +@com.fasterxml.jackson.databind.annotation.JsonDeserialize(builder = JacksonBuilderSingular.JacksonBuilderSingularBuilder.class) +public class JacksonBuilderSingular { + @JsonAnySetter + private Map any; + @JsonProperty("v_a_l_u_e_s") + private List values; + @JsonAnySetter + private ImmutableMap guavaAny; + @JsonProperty("guava_v_a_l_u_e_s") + private ImmutableList guavaValues; + @java.lang.SuppressWarnings("all") + JacksonBuilderSingular(final Map any, final List values, final ImmutableMap guavaAny, final ImmutableList guavaValues) { + this.any = any; + this.values = values; + this.guavaAny = guavaAny; + this.guavaValues = guavaValues; + } + @java.lang.SuppressWarnings("all") + @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "", buildMethodName = "build") + public static class JacksonBuilderSingularBuilder { + @java.lang.SuppressWarnings("all") + private java.util.ArrayList any$key; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList any$value; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList values; + @java.lang.SuppressWarnings("all") + private com.google.common.collect.ImmutableMap.Builder guavaAny; + @java.lang.SuppressWarnings("all") + private com.google.common.collect.ImmutableList.Builder guavaValues; + @java.lang.SuppressWarnings("all") + JacksonBuilderSingularBuilder() { + } + @JsonAnySetter + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final String anyKey, final Object anyValue) { + if (this.any$key == null) { + this.any$key = new java.util.ArrayList(); + this.any$value = new java.util.ArrayList(); + } + this.any$key.add(anyKey); + this.any$value.add(anyValue); + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final java.util.Map any) { + if (any == null) { + throw new java.lang.NullPointerException("any cannot be null"); + } + if (this.any$key == null) { + this.any$key = new java.util.ArrayList(); + this.any$value = new java.util.ArrayList(); + } + for (final java.util.Map.Entry $lombokEntry : any.entrySet()) { + this.any$key.add($lombokEntry.getKey()); + this.any$value.add($lombokEntry.getValue()); + } + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearAny() { + if (this.any$key != null) { + this.any$key.clear(); + this.any$value.clear(); + } + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder value(final String value) { + if (this.values == null) this.values = new java.util.ArrayList(); + this.values.add(value); + return this; + } + @JsonProperty("v_a_l_u_e_s") + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder values(final java.util.Collection values) { + if (values == null) { + throw new java.lang.NullPointerException("values cannot be null"); + } + if (this.values == null) this.values = new java.util.ArrayList(); + this.values.addAll(values); + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearValues() { + if (this.values != null) this.values.clear(); + return this; + } + @JsonAnySetter + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final String key, final Object value) { + if (this.guavaAny == null) this.guavaAny = com.google.common.collect.ImmutableMap.builder(); + this.guavaAny.put(key, value); + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final java.util.Map guavaAny) { + if (guavaAny == null) { + throw new java.lang.NullPointerException("guavaAny cannot be null"); + } + if (this.guavaAny == null) this.guavaAny = com.google.common.collect.ImmutableMap.builder(); + this.guavaAny.putAll(guavaAny); + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaAny() { + this.guavaAny = null; + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValue(final String guavaValue) { + if (this.guavaValues == null) this.guavaValues = com.google.common.collect.ImmutableList.builder(); + this.guavaValues.add(guavaValue); + return this; + } + @JsonProperty("guava_v_a_l_u_e_s") + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValues(final java.lang.Iterable guavaValues) { + if (guavaValues == null) { + throw new java.lang.NullPointerException("guavaValues cannot be null"); + } + if (this.guavaValues == null) this.guavaValues = com.google.common.collect.ImmutableList.builder(); + this.guavaValues.addAll(guavaValues); + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaValues() { + this.guavaValues = null; + return this; + } + @java.lang.SuppressWarnings("all") + public JacksonBuilderSingular build() { + java.util.Map any; + switch (this.any$key == null ? 0 : this.any$key.size()) { + case 0: + any = java.util.Collections.emptyMap(); + break; + case 1: + any = java.util.Collections.singletonMap(this.any$key.get(0), this.any$value.get(0)); + break; + default: + any = new java.util.LinkedHashMap(this.any$key.size() < 1073741824 ? 1 + this.any$key.size() + (this.any$key.size() - 3) / 3 : java.lang.Integer.MAX_VALUE); + for (int $i = 0; $i < this.any$key.size(); $i++) any.put(this.any$key.get($i), (Object) this.any$value.get($i)); + any = java.util.Collections.unmodifiableMap(any); + } + java.util.List values; + switch (this.values == null ? 0 : this.values.size()) { + case 0: + values = java.util.Collections.emptyList(); + break; + case 1: + values = java.util.Collections.singletonList(this.values.get(0)); + break; + default: + values = java.util.Collections.unmodifiableList(new java.util.ArrayList(this.values)); + } + com.google.common.collect.ImmutableMap guavaAny = this.guavaAny == null ? com.google.common.collect.ImmutableMap.of() : this.guavaAny.build(); + com.google.common.collect.ImmutableList guavaValues = this.guavaValues == null ? com.google.common.collect.ImmutableList.of() : this.guavaValues.build(); + return new JacksonBuilderSingular(any, values, guavaAny, guavaValues); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "JacksonBuilderSingular.JacksonBuilderSingularBuilder(any$key=" + this.any$key + ", any$value=" + this.any$value + ", values=" + this.values + ", guavaAny=" + this.guavaAny + ", guavaValues=" + this.guavaValues + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static JacksonBuilderSingular.JacksonBuilderSingularBuilder builder() { + return new JacksonBuilderSingular.JacksonBuilderSingularBuilder(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerCommons.java b/test/transform/resource/after-delombok/LoggerCommons.java index 954e730b..4b943da7 100644 --- a/test/transform/resource/after-delombok/LoggerCommons.java +++ b/test/transform/resource/after-delombok/LoggerCommons.java @@ -10,3 +10,8 @@ class LoggerCommonsWithDifferentName { @java.lang.SuppressWarnings("all") private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("DifferentName"); } +class LoggerCommonsWithStaticField { + @java.lang.SuppressWarnings("all") + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LoggerCommonsWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerCustomWithTopicAndName.java b/test/transform/resource/after-delombok/LoggerCustomWithTopicAndName.java index abb785b9..4db02cc1 100644 --- a/test/transform/resource/after-delombok/LoggerCustomWithTopicAndName.java +++ b/test/transform/resource/after-delombok/LoggerCustomWithTopicAndName.java @@ -3,6 +3,12 @@ class LoggerCustomLog { private static final MyLoggerFactory log = MyLoggerFactory.create(LoggerCustomLog.class.getName(), "t", null, LoggerCustomLog.class, "t"); } +class LoggerCustomLogWithStaticField { + @java.lang.SuppressWarnings("all") + private static final MyLoggerFactory log = MyLoggerFactory.create(LoggerCustomLogWithStaticField.class.getName(), LoggerCustomLogWithStaticField.TOPIC, null, LoggerCustomLogWithStaticField.class, LoggerCustomLogWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} + class MyLoggerFactory { static MyLoggerFactory create(String name, String t1, Object o, Class clazz, String t2) { return null; diff --git a/test/transform/resource/after-delombok/LoggerJBossLog.java b/test/transform/resource/after-delombok/LoggerJBossLog.java index 41c18805..5fd98aa6 100644 --- a/test/transform/resource/after-delombok/LoggerJBossLog.java +++ b/test/transform/resource/after-delombok/LoggerJBossLog.java @@ -17,3 +17,9 @@ class LoggerJBossLogWithDifferentLoggerName { @java.lang.SuppressWarnings("all") private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger("DifferentLogger"); } + +class LoggerJBossLogWithStaticField { + @java.lang.SuppressWarnings("all") + private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LoggerJBossLogWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerJul.java b/test/transform/resource/after-delombok/LoggerJul.java index 63f96733..cfb44fde 100644 --- a/test/transform/resource/after-delombok/LoggerJul.java +++ b/test/transform/resource/after-delombok/LoggerJul.java @@ -10,3 +10,8 @@ class LoggerJulWithDifferentName { @java.lang.SuppressWarnings("all") private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger("DifferentName"); } +class LoggerJulWithStaticField { + @java.lang.SuppressWarnings("all") + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggerJulWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerLog4j.java b/test/transform/resource/after-delombok/LoggerLog4j.java index 7d9d4409..cef83621 100644 --- a/test/transform/resource/after-delombok/LoggerLog4j.java +++ b/test/transform/resource/after-delombok/LoggerLog4j.java @@ -10,3 +10,8 @@ class LoggerLog4jWithDifferentName { @java.lang.SuppressWarnings("all") private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("DifferentName"); } +class LoggerLog4jWithStaticField { + @java.lang.SuppressWarnings("all") + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LoggerLog4jWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} diff --git a/test/transform/resource/after-delombok/LoggerLog4j2.java b/test/transform/resource/after-delombok/LoggerLog4j2.java index 3d8b7b5b..b32c7722 100644 --- a/test/transform/resource/after-delombok/LoggerLog4j2.java +++ b/test/transform/resource/after-delombok/LoggerLog4j2.java @@ -10,3 +10,8 @@ class LoggerLog4j2WithDifferentName { @java.lang.SuppressWarnings("all") private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger("DifferentName"); } +class LoggerLog4j2WithStaticField { + @java.lang.SuppressWarnings("all") + private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LoggerLog4j2WithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4j.java b/test/transform/resource/after-delombok/LoggerSlf4j.java index 68d685f0..70f11ae4 100644 --- a/test/transform/resource/after-delombok/LoggerSlf4j.java +++ b/test/transform/resource/after-delombok/LoggerSlf4j.java @@ -17,3 +17,20 @@ class LoggerSlf4jWithDifferentLoggerName { @java.lang.SuppressWarnings("all") private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("DifferentLogger"); } + +class LoggerSlf4jWithStaticField { + @java.lang.SuppressWarnings("all") + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} + +class LoggerSlf4jWithTwoStaticFields { + @java.lang.SuppressWarnings("all") + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jWithTwoStaticFields.TOPIC + LoggerSlf4jWithTwoStaticFields.TOPIC); + static final String TOPIC = "StaticField"; +} + +class LoggerSlf4jWithTwoLiterals { + @java.lang.SuppressWarnings("all") + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("A" + "B"); +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4jInvalidTopic.java b/test/transform/resource/after-delombok/LoggerSlf4jInvalidTopic.java new file mode 100644 index 00000000..86e6ae2c --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jInvalidTopic.java @@ -0,0 +1,5 @@ +import lombok.extern.slf4j.Slf4j; + +@Slf4j(topic = 42) +class LoggerSlf4jWithIntegerTopic { +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerXSlf4j.java b/test/transform/resource/after-delombok/LoggerXSlf4j.java index 781733cf..ba0ec3f8 100644 --- a/test/transform/resource/after-delombok/LoggerXSlf4j.java +++ b/test/transform/resource/after-delombok/LoggerXSlf4j.java @@ -10,3 +10,8 @@ class LoggerXSlf4jWithDifferentName { @java.lang.SuppressWarnings("all") private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger("DifferentName"); } +class LoggerXSlf4jWithStaticField { + @java.lang.SuppressWarnings("all") + private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LoggerXSlf4jWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/SkipSuppressWarnings.java b/test/transform/resource/after-delombok/SkipSuppressWarnings.java new file mode 100644 index 00000000..151d4e17 --- /dev/null +++ b/test/transform/resource/after-delombok/SkipSuppressWarnings.java @@ -0,0 +1,24 @@ +class SkipSuppressWarnings { + private String field = ""; + private final java.util.concurrent.atomic.AtomicReference field2 = new java.util.concurrent.atomic.AtomicReference(); + + public String getField() { + return this.field; + } + + @java.lang.SuppressWarnings({"unchecked"}) + public String getField2() { + java.lang.Object value = this.field2.get(); + if (value == null) { + synchronized (this.field2) { + value = this.field2.get(); + if (value == null) { + final String actualValue = ""; + value = actualValue == null ? this.field2 : actualValue; + this.field2.set(value); + } + } + } + return (String) (value == this.field2 ? null : value); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java index c347e41c..c3fa86f2 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasic.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -81,10 +81,10 @@ public class SuperBuilderBasic { return new SuperBuilderBasic.Parent.ParentBuilderImpl(); } } - public static class Child extends Parent { + public static class Child extends SuperBuilderBasic.Parent { double field3; @java.lang.SuppressWarnings("all") - public static abstract class ChildBuilder> extends Parent.ParentBuilder { + public static abstract class ChildBuilder> extends SuperBuilderBasic.Parent.ParentBuilder { @java.lang.SuppressWarnings("all") private double field3; @java.lang.Override diff --git a/test/transform/resource/after-delombok/SuperBuilderCustomized.java b/test/transform/resource/after-delombok/SuperBuilderCustomized.java index bffa72fa..f66133c9 100644 --- a/test/transform/resource/after-delombok/SuperBuilderCustomized.java +++ b/test/transform/resource/after-delombok/SuperBuilderCustomized.java @@ -23,6 +23,13 @@ public class SuperBuilderCustomized { } } int field1; + protected Parent(ParentBuilder b) { + if (b.field1 == 0) throw new IllegalArgumentException("field1 must be != 0"); + this.field1 = b.field1; + } + public static SuperBuilderCustomized.Parent.ParentBuilder builder(int field1) { + return new SuperBuilderCustomized.Parent.ParentBuilderImpl().field1(field1); + } @java.lang.SuppressWarnings("all") private static final class ParentBuilderImpl extends SuperBuilderCustomized.Parent.ParentBuilder { @java.lang.SuppressWarnings("all") @@ -39,14 +46,6 @@ public class SuperBuilderCustomized { return new SuperBuilderCustomized.Parent(this); } } - @java.lang.SuppressWarnings("all") - protected Parent(final SuperBuilderCustomized.Parent.ParentBuilder b) { - this.field1 = b.field1; - } - @java.lang.SuppressWarnings("all") - public static SuperBuilderCustomized.Parent.ParentBuilder builder() { - return new SuperBuilderCustomized.Parent.ParentBuilderImpl(); - } } public static class Child extends Parent { private static final class ChildBuilderImpl extends ChildBuilder { diff --git a/test/transform/resource/after-delombok/TypeUseAnnotations.java b/test/transform/resource/after-delombok/TypeUseAnnotations.java index 1e1536bf..fbf32577 100644 --- a/test/transform/resource/after-delombok/TypeUseAnnotations.java +++ b/test/transform/resource/after-delombok/TypeUseAnnotations.java @@ -7,8 +7,18 @@ import java.util.List; } class TypeUseAnnotations { List<@TA(x = 5) String> foo; + List bar; + + class Inner { + } + @java.lang.SuppressWarnings("all") public List<@TA(x = 5) String> getFoo() { return this.foo; } + + @java.lang.SuppressWarnings("all") + public List getBar() { + return this.bar; + } } diff --git a/test/transform/resource/after-delombok/ValLambda.java b/test/transform/resource/after-delombok/ValLambda.java index 24ae3b5f..910e3506 100644 --- a/test/transform/resource/after-delombok/ValLambda.java +++ b/test/transform/resource/after-delombok/ValLambda.java @@ -1,4 +1,6 @@ // version 8: +import java.io.Serializable; + class ValLambda { static { final java.lang.Runnable foo = (System.currentTimeMillis() > 0) ? (Runnable) () -> { @@ -15,8 +17,8 @@ class ValLambda { }; } - public void easyIntersectionLambda() { - final java.lang.Runnable foo = (Runnable & java.io.Serializable) () -> { + public void intersectionLambda() { + final java.io.Serializable foo = (Runnable & Serializable) () -> { }; final java.io.Serializable bar = (java.io.Serializable & Runnable) () -> { }; diff --git a/test/transform/resource/after-delombok/ValueStaticConstructorOf.java b/test/transform/resource/after-delombok/ValueStaticConstructorOf.java index fe75f823..e4564628 100644 --- a/test/transform/resource/after-delombok/ValueStaticConstructorOf.java +++ b/test/transform/resource/after-delombok/ValueStaticConstructorOf.java @@ -23,12 +23,12 @@ public final class ValueStaticConstructorOf { if (o == this) return true; if (!(o instanceof ValueStaticConstructorOf)) return false; final ValueStaticConstructorOf other = (ValueStaticConstructorOf) o; - final java.lang.Object this$name = this.getName(); - final java.lang.Object other$name = other.getName(); - if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; final java.lang.Object this$price = this.getPrice(); final java.lang.Object other$price = other.getPrice(); if (this$price == null ? other$price != null : !this$price.equals(other$price)) return false; + final java.lang.Object this$name = this.getName(); + final java.lang.Object other$name = other.getName(); + if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; return true; } @java.lang.Override @@ -36,10 +36,10 @@ public final class ValueStaticConstructorOf { public int hashCode() { final int PRIME = 59; int result = 1; - final java.lang.Object $name = this.getName(); - result = result * PRIME + ($name == null ? 43 : $name.hashCode()); final java.lang.Object $price = this.getPrice(); result = result * PRIME + ($price == null ? 43 : $price.hashCode()); + final java.lang.Object $name = this.getName(); + result = result * PRIME + ($name == null ? 43 : $name.hashCode()); return result; } @java.lang.Override diff --git a/test/transform/resource/after-ecj/BuilderConstructorJavadoc.java b/test/transform/resource/after-ecj/BuilderConstructorJavadoc.java new file mode 100644 index 00000000..bb3916e8 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderConstructorJavadoc.java @@ -0,0 +1,40 @@ +import java.util.List; +class BuilderConstructorJavadoc { + public static class BuilderConstructorJavadocBuilder { + private @java.lang.SuppressWarnings("all") int basic; + private @java.lang.SuppressWarnings("all") int multiline; + private @java.lang.SuppressWarnings("all") int predef; + private @java.lang.SuppressWarnings("all") int predefWithJavadoc; + public BuilderConstructorJavadocBuilder predef(final int x) { + this.predef = x; + return this; + } + public BuilderConstructorJavadocBuilder predefWithJavadoc(final int x) { + this.predefWithJavadoc = x; + return this; + } + @java.lang.SuppressWarnings("all") BuilderConstructorJavadocBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder basic(final int basic) { + this.basic = basic; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder multiline(final int multiline) { + this.multiline = multiline; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderConstructorJavadoc build() { + return new BuilderConstructorJavadoc(this.basic, this.multiline, this.predef, this.predefWithJavadoc); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((((("BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder(basic=" + this.basic) + ", multiline=") + this.multiline) + ", predef=") + this.predef) + ", predefWithJavadoc=") + this.predefWithJavadoc) + ")"); + } + } + @lombok.Builder BuilderConstructorJavadoc(int basic, int multiline, int predef, int predefWithJavadoc) { + super(); + } + public static @java.lang.SuppressWarnings("all") BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder builder() { + return new BuilderConstructorJavadoc.BuilderConstructorJavadocBuilder(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderDefaults.java b/test/transform/resource/after-ecj/BuilderDefaults.java index 46f55bef..c9be219d 100644 --- a/test/transform/resource/after-ecj/BuilderDefaults.java +++ b/test/transform/resource/after-ecj/BuilderDefaults.java @@ -72,25 +72,25 @@ public final @Value @Builder class BuilderDefaults { final BuilderDefaults other = (BuilderDefaults) o; if ((this.getX() != other.getX())) return false; + if ((this.getZ() != other.getZ())) + return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); if (((this$name == null) ? (other$name != null) : (! this$name.equals(other$name)))) return false; - if ((this.getZ() != other.getZ())) - 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.getX()); - final java.lang.Object $name = this.getName(); - result = ((result * PRIME) + (($name == null) ? 43 : $name.hashCode())); final long $z = this.getZ(); result = ((result * PRIME) + (int) ($z ^ ($z >>> 32))); + final java.lang.Object $name = this.getName(); + result = ((result * PRIME) + (($name == null) ? 43 : $name.hashCode())); return result; } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (((((("BuilderDefaults(x=" + this.getX()) + ", name=") + this.getName()) + ", z=") + this.getZ()) + ")"); } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java b/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java index 5bd4e1b3..7c8ff0ed 100644 --- a/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java +++ b/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java @@ -9,6 +9,7 @@ class CheckerFrameworkSuperBuilder { private @java.lang.SuppressWarnings("all") int z; private @java.lang.SuppressWarnings("all") java.util.ArrayList names; public ParentBuilder() { + super(); } protected abstract @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); public abstract @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(final @org.checkerframework.checker.builder.qual.CalledMethods({"y", "z"}) CheckerFrameworkSuperBuilder.Parent.ParentBuilder this); @@ -52,6 +53,7 @@ class CheckerFrameworkSuperBuilder { } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends CheckerFrameworkSuperBuilder.Parent.ParentBuilder { private ParentBuilderImpl() { + super(); } protected @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl self() { return this; @@ -92,36 +94,38 @@ class CheckerFrameworkSuperBuilder { return new CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl(); } } - public static @lombok.experimental.SuperBuilder class Child extends Parent { - public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder { + public static @lombok.experimental.SuperBuilder class ZChild extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ZChildBuilder> extends Parent.ParentBuilder { private @java.lang.SuppressWarnings("all") int a$value; private @java.lang.SuppressWarnings("all") boolean a$set; private @java.lang.SuppressWarnings("all") int b; - public ChildBuilder() { + public ZChildBuilder() { + super(); } protected abstract @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); - public abstract @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(final @org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.Child.ChildBuilder this); - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B a(final @org.checkerframework.checker.builder.qual.NotCalledMethods("a") CheckerFrameworkSuperBuilder.Child.ChildBuilder this, final int a) { + public abstract @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(final @org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this); + public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B a(final @org.checkerframework.checker.builder.qual.NotCalledMethods("a") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this, final int a) { this.a$value = a; a$set = true; return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B b(final @org.checkerframework.checker.builder.qual.NotCalledMethods("b") CheckerFrameworkSuperBuilder.Child.ChildBuilder this, final int b) { + public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B b(final @org.checkerframework.checker.builder.qual.NotCalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this, final int b) { this.b = b; return self(); } public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") java.lang.String toString() { - return (((((("CheckerFrameworkSuperBuilder.Child.ChildBuilder(super=" + super.toString()) + ", a$value=") + this.a$value) + ", b=") + this.b) + ")"); + return (((((("CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder(super=" + super.toString()) + ", a$value=") + this.a$value) + ", b=") + this.b) + ")"); } } - private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends CheckerFrameworkSuperBuilder.Child.ChildBuilder { - private ChildBuilderImpl() { + private static final @java.lang.SuppressWarnings("all") class ZChildBuilderImpl extends CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder { + private ZChildBuilderImpl() { + super(); } - protected @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Child.ChildBuilderImpl self() { + protected @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { return this; } - public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Child build(final @org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.Child.ChildBuilderImpl this) { - return new CheckerFrameworkSuperBuilder.Child(this); + public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild build(final @org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl this) { + return new CheckerFrameworkSuperBuilder.ZChild(this); } } @lombok.Builder.Default int a; @@ -129,18 +133,19 @@ class CheckerFrameworkSuperBuilder { private static @java.lang.SuppressWarnings("all") int $default$a() { return 1; } - protected @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") Child(final CheckerFrameworkSuperBuilder.Child.ChildBuilder b) { + protected @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") ZChild(final CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder b) { super(b); if (b.a$set) this.a = b.a$value; else - this.a = CheckerFrameworkSuperBuilder.Child.$default$a(); + this.a = CheckerFrameworkSuperBuilder.ZChild.$default$a(); this.b = b.b; } - public static @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Child.ChildBuilder builder() { - return new CheckerFrameworkSuperBuilder.Child.ChildBuilderImpl(); + public static @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder builder() { + return new CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl(); } } CheckerFrameworkSuperBuilder() { + super(); } } diff --git a/test/transform/resource/after-ecj/DelegateAlreadyImplemented.java b/test/transform/resource/after-ecj/DelegateAlreadyImplemented.java new file mode 100644 index 00000000..1e12f405 --- /dev/null +++ b/test/transform/resource/after-ecj/DelegateAlreadyImplemented.java @@ -0,0 +1,29 @@ +public class DelegateAlreadyImplemented { + private @lombok.experimental.Delegate A a; + public DelegateAlreadyImplemented() { + super(); + } + public void a() { + } + public void b(java.util.List l) { + } + public void c(java.util.List l, String[] a, Integer... varargs) { + } + public void d(String[][][][] d) { + } + public void e(Y x) { + } + public @SuppressWarnings("unchecked") void f(T s, java.util.List l, T[] a, T... varargs) { + } + public void g(Number g) { + } +} +interface A { + public void a(); + public void b(java.util.List l); + public @SuppressWarnings("unchecked") void c(java.util.List l, String[] a, T... varargs); + public void d(String[][][][] d); + public X e(X x); + public @SuppressWarnings("unchecked") void f(T2 s, java.util.List l, T2[] a, T2... varargs); + public void g(G g); +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/DelegateGenerics.java b/test/transform/resource/after-ecj/DelegateGenerics.java new file mode 100644 index 00000000..97b05102 --- /dev/null +++ b/test/transform/resource/after-ecj/DelegateGenerics.java @@ -0,0 +1,24 @@ +public class DelegateGenerics { + @lombok.experimental.Delegate I1 target; + public DelegateGenerics() { + super(); + } + public @java.lang.SuppressWarnings("all") T a(final T a) { + return this.target.a(a); + } + public @java.lang.SuppressWarnings("all") java.lang.String i(final java.lang.String a) { + return this.target.i(a); + } + public @java.lang.SuppressWarnings("all") java.lang.Integer t(final java.lang.Integer t) { + return this.target.t(t); + } +} +interface I1 extends I2 { +} +interface I2 extends I3 { +} +interface I3 { + public T t(T t); + public I i(I a); + public A a(A a); +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/DelegateWithVarargs2.java b/test/transform/resource/after-ecj/DelegateWithVarargs2.java new file mode 100644 index 00000000..ed0cddf5 --- /dev/null +++ b/test/transform/resource/after-ecj/DelegateWithVarargs2.java @@ -0,0 +1,17 @@ +import lombok.experimental.Delegate; +class DelegateWithVarargs2 { + public class B { + public B() { + super(); + } + public void varargs(Object[]... keys) { + } + } + private @Delegate DelegateWithVarargs2.B bar; + DelegateWithVarargs2() { + super(); + } + public @java.lang.SuppressWarnings("all") void varargs(final java.lang.Object[]... keys) { + this.bar.varargs(keys); + } +} diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeAnnotated.java b/test/transform/resource/after-ecj/EqualsAndHashCodeAnnotated.java new file mode 100644 index 00000000..4e377fb4 --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeAnnotated.java @@ -0,0 +1,53 @@ +import java.lang.annotation.*; +@lombok.EqualsAndHashCode class EqualsAndHashCodeAnnotated { + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.SOURCE) @interface Annotated { + } + @Annotated int primitive; + @Annotated Object object; + int @Annotated [] primitiveValues; + int @Annotated [] @Annotated [] morePrimitiveValues; + Integer @Annotated [] objectValues; + Integer @Annotated [] @Annotated [] moreObjectValues; + EqualsAndHashCodeAnnotated() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCodeAnnotated))) + return false; + final EqualsAndHashCodeAnnotated other = (EqualsAndHashCodeAnnotated) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.primitive != other.primitive)) + return false; + final java.lang.Object this$object = this.object; + final java.lang.Object other$object = other.object; + if (((this$object == null) ? (other$object != null) : (! this$object.equals(other$object)))) + return false; + if ((! java.util.Arrays.equals(this.primitiveValues, other.primitiveValues))) + return false; + if ((! java.util.Arrays.deepEquals(this.morePrimitiveValues, other.morePrimitiveValues))) + return false; + if ((! java.util.Arrays.deepEquals(this.objectValues, other.objectValues))) + return false; + if ((! java.util.Arrays.deepEquals(this.moreObjectValues, other.moreObjectValues))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCodeAnnotated); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.primitive); + final java.lang.Object $object = this.object; + result = ((result * PRIME) + (($object == null) ? 43 : $object.hashCode())); + result = ((result * PRIME) + java.util.Arrays.hashCode(this.primitiveValues)); + result = ((result * PRIME) + java.util.Arrays.deepHashCode(this.morePrimitiveValues)); + result = ((result * PRIME) + java.util.Arrays.deepHashCode(this.objectValues)); + result = ((result * PRIME) + java.util.Arrays.deepHashCode(this.moreObjectValues)); + return result; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeRank.java b/test/transform/resource/after-ecj/EqualsAndHashCodeRank.java new file mode 100644 index 00000000..ef221261 --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeRank.java @@ -0,0 +1,36 @@ +import lombok.EqualsAndHashCode; +public @EqualsAndHashCode class EqualsAndHashCodeRank { + @EqualsAndHashCode.Include int a; + @EqualsAndHashCode.Include(rank = 10) int b; + @EqualsAndHashCode.Include int c; + public EqualsAndHashCodeRank() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCodeRank))) + return false; + final EqualsAndHashCodeRank other = (EqualsAndHashCodeRank) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.a != other.a)) + return false; + if ((this.c != other.c)) + return false; + if ((this.b != other.b)) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCodeRank); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.a); + result = ((result * PRIME) + this.c); + result = ((result * PRIME) + this.b); + return result; + } +} diff --git a/test/transform/resource/after-ecj/GetterLazyArguments.java b/test/transform/resource/after-ecj/GetterLazyArguments.java new file mode 100644 index 00000000..41f1771f --- /dev/null +++ b/test/transform/resource/after-ecj/GetterLazyArguments.java @@ -0,0 +1,106 @@ +class GetterLazyArguments { + private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference field1 = new java.util.concurrent.atomic.AtomicReference(); + private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference field2 = new java.util.concurrent.atomic.AtomicReference(); + private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference field3 = new java.util.concurrent.atomic.AtomicReference(); + private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference field4 = new java.util.concurrent.atomic.AtomicReference(); + private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference field5 = new java.util.concurrent.atomic.AtomicReference(); + GetterLazyArguments() { + super(); + } + static String fun() { + return null; + } + static String stringInt(String arg1, Integer arg2) { + return null; + } + static String stringRunnable(String arg1, Runnable arg2) { + return null; + } + public @java.lang.SuppressWarnings({"all", "unchecked"}) String getField1() { + java.lang.Object value = this.field1.get(); + if ((value == null)) + { + synchronized (this.field1) + { + value = this.field1.get(); + if ((value == null)) + { + final String actualValue = stringInt("a", 1); + value = ((actualValue == null) ? this.field1 : actualValue); + this.field1.set(value); + } + } + } + return (String) ((value == this.field1) ? null : value); + } + public @java.lang.SuppressWarnings({"all", "unchecked"}) String getField2() { + java.lang.Object value = this.field2.get(); + if ((value == null)) + { + synchronized (this.field2) + { + value = this.field2.get(); + if ((value == null)) + { + final String actualValue = stringInt((true ? "a" : "b"), (true ? 1 : 0)); + value = ((actualValue == null) ? this.field2 : actualValue); + this.field2.set(value); + } + } + } + return (String) ((value == this.field2) ? null : value); + } + public @java.lang.SuppressWarnings({"all", "unchecked"}) String getField3() { + java.lang.Object value = this.field3.get(); + if ((value == null)) + { + synchronized (this.field3) + { + value = this.field3.get(); + if ((value == null)) + { + final String actualValue = stringInt("a", (true ? 1 : 0)); + value = ((actualValue == null) ? this.field3 : actualValue); + this.field3.set(value); + } + } + } + return (String) ((value == this.field3) ? null : value); + } + public @java.lang.SuppressWarnings({"all", "unchecked"}) String getField4() { + java.lang.Object value = this.field4.get(); + if ((value == null)) + { + synchronized (this.field4) + { + value = this.field4.get(); + if ((value == null)) + { + final String actualValue = stringRunnable(fun(), () -> { +}); + value = ((actualValue == null) ? this.field4 : actualValue); + this.field4.set(value); + } + } + } + return (String) ((value == this.field4) ? null : value); + } + public @java.lang.SuppressWarnings({"all", "unchecked"}) String getField5() { + java.lang.Object value = this.field5.get(); + if ((value == null)) + { + synchronized (this.field5) + { + value = this.field5.get(); + if ((value == null)) + { + final String actualValue = stringRunnable("a", () -> { +}); + value = ((actualValue == null) ? this.field5 : actualValue); + this.field5.set(value); + } + } + } + return (String) ((value == this.field5) ? null : value); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/JacksonBuilderSingular.java b/test/transform/resource/after-ecj/JacksonBuilderSingular.java new file mode 100644 index 00000000..50f6a797 --- /dev/null +++ b/test/transform/resource/after-ecj/JacksonBuilderSingular.java @@ -0,0 +1,164 @@ +import java.util.List; +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import lombok.Builder; +import lombok.Singular; +import lombok.extern.jackson.Jacksonized; +public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDeserialize(builder = JacksonBuilderSingular.JacksonBuilderSingularBuilder.class) class JacksonBuilderSingular { + public static @java.lang.SuppressWarnings("all") @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "",buildMethodName = "build") class JacksonBuilderSingularBuilder { + private @java.lang.SuppressWarnings("all") java.util.ArrayList any$key; + private @java.lang.SuppressWarnings("all") java.util.ArrayList any$value; + private @java.lang.SuppressWarnings("all") java.util.ArrayList values; + private @java.lang.SuppressWarnings("all") com.google.common.collect.ImmutableMap.Builder guavaAny; + private @java.lang.SuppressWarnings("all") com.google.common.collect.ImmutableList.Builder guavaValues; + @java.lang.SuppressWarnings("all") JacksonBuilderSingularBuilder() { + super(); + } + public @JsonAnySetter @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final String anyKey, final Object anyValue) { + if ((this.any$key == null)) + { + this.any$key = new java.util.ArrayList(); + this.any$value = new java.util.ArrayList(); + } + this.any$key.add(anyKey); + this.any$value.add(anyValue); + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final java.util.Map any) { + if ((any == null)) + { + throw new java.lang.NullPointerException("any cannot be null"); + } + if ((this.any$key == null)) + { + this.any$key = new java.util.ArrayList(); + this.any$value = new java.util.ArrayList(); + } + for (java.util.Map.Entry $lombokEntry : any.entrySet()) + { + this.any$key.add($lombokEntry.getKey()); + this.any$value.add($lombokEntry.getValue()); + } + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder clearAny() { + if ((this.any$key != null)) + { + this.any$key.clear(); + this.any$value.clear(); + } + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder value(final String value) { + if ((this.values == null)) + this.values = new java.util.ArrayList(); + this.values.add(value); + return this; + } + public @JsonProperty("v_a_l_u_e_s") @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder values(final java.util.Collection values) { + if ((values == null)) + { + throw new java.lang.NullPointerException("values cannot be null"); + } + if ((this.values == null)) + this.values = new java.util.ArrayList(); + this.values.addAll(values); + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder clearValues() { + if ((this.values != null)) + this.values.clear(); + return this; + } + public @JsonAnySetter @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final String key, final Object value) { + if ((this.guavaAny == null)) + this.guavaAny = com.google.common.collect.ImmutableMap.builder(); + this.guavaAny.put(key, value); + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final java.util.Map guavaAny) { + if ((guavaAny == null)) + { + throw new java.lang.NullPointerException("guavaAny cannot be null"); + } + if ((this.guavaAny == null)) + this.guavaAny = com.google.common.collect.ImmutableMap.builder(); + this.guavaAny.putAll(guavaAny); + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaAny() { + this.guavaAny = null; + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValue(final String guavaValue) { + if ((this.guavaValues == null)) + this.guavaValues = com.google.common.collect.ImmutableList.builder(); + this.guavaValues.add(guavaValue); + return this; + } + public @JsonProperty("guava_v_a_l_u_e_s") @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValues(final java.lang.Iterable guavaValues) { + if ((guavaValues == null)) + { + throw new java.lang.NullPointerException("guavaValues cannot be null"); + } + if ((this.guavaValues == null)) + this.guavaValues = com.google.common.collect.ImmutableList.builder(); + this.guavaValues.addAll(guavaValues); + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaValues() { + this.guavaValues = null; + return this; + } + public @java.lang.SuppressWarnings("all") JacksonBuilderSingular build() { + java.util.Map any; + switch (((this.any$key == null) ? 0 : this.any$key.size())) { + case 0 : + any = java.util.Collections.emptyMap(); + break; + case 1 : + any = java.util.Collections.singletonMap(this.any$key.get(0), this.any$value.get(0)); + break; + default : + any = new java.util.LinkedHashMap(((this.any$key.size() < 0x40000000) ? ((1 + this.any$key.size()) + ((this.any$key.size() - 3) / 3)) : java.lang.Integer.MAX_VALUE)); + for (int $i = 0;; ($i < this.any$key.size()); $i ++) + any.put(this.any$key.get($i), this.any$value.get($i)); + any = java.util.Collections.unmodifiableMap(any); + } + java.util.List values; + switch (((this.values == null) ? 0 : this.values.size())) { + case 0 : + values = java.util.Collections.emptyList(); + break; + case 1 : + values = java.util.Collections.singletonList(this.values.get(0)); + break; + default : + values = java.util.Collections.unmodifiableList(new java.util.ArrayList(this.values)); + } + com.google.common.collect.ImmutableMap guavaAny = ((this.guavaAny == null) ? com.google.common.collect.ImmutableMap.of() : this.guavaAny.build()); + com.google.common.collect.ImmutableList guavaValues = ((this.guavaValues == null) ? com.google.common.collect.ImmutableList.of() : this.guavaValues.build()); + return new JacksonBuilderSingular(any, values, guavaAny, guavaValues); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((((((("JacksonBuilderSingular.JacksonBuilderSingularBuilder(any$key=" + this.any$key) + ", any$value=") + this.any$value) + ", values=") + this.values) + ", guavaAny=") + this.guavaAny) + ", guavaValues=") + this.guavaValues) + ")"); + } + } + private @JsonAnySetter @Singular("any") Map any; + private @JsonProperty("v_a_l_u_e_s") @Singular List values; + private @JsonAnySetter @Singular("guavaAny") ImmutableMap guavaAny; + private @JsonProperty("guava_v_a_l_u_e_s") @Singular ImmutableList guavaValues; + @java.lang.SuppressWarnings("all") JacksonBuilderSingular(final Map any, final List values, final ImmutableMap guavaAny, final ImmutableList guavaValues) { + super(); + this.any = any; + this.values = values; + this.guavaAny = guavaAny; + this.guavaValues = guavaValues; + } + public static @java.lang.SuppressWarnings("all") JacksonBuilderSingular.JacksonBuilderSingularBuilder builder() { + return new JacksonBuilderSingular.JacksonBuilderSingularBuilder(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerCommons.java b/test/transform/resource/after-ecj/LoggerCommons.java index df102a12..b2ca055f 100644 --- a/test/transform/resource/after-ecj/LoggerCommons.java +++ b/test/transform/resource/after-ecj/LoggerCommons.java @@ -22,4 +22,13 @@ import lombok.extern.apachecommons.CommonsLog; LoggerCommonsWithDifferentName() { super(); } +} +@CommonsLog(topic = LoggerCommonsWithStaticField.TOPIC) class LoggerCommonsWithStaticField { + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LoggerCommonsWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerCommonsWithStaticField() { + super(); + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerCustomWithTopicAndName.java b/test/transform/resource/after-ecj/LoggerCustomWithTopicAndName.java index 91cf6d8d..f6f85744 100644 --- a/test/transform/resource/after-ecj/LoggerCustomWithTopicAndName.java +++ b/test/transform/resource/after-ecj/LoggerCustomWithTopicAndName.java @@ -6,6 +6,15 @@ super(); } } +@lombok.CustomLog(topic = LoggerCustomLogWithStaticField.TOPIC) class LoggerCustomLogWithStaticField { + private static final MyLoggerFactory log = MyLoggerFactory.create(LoggerCustomLogWithStaticField.class.getName(), LoggerCustomLogWithStaticField.TOPIC, null, LoggerCustomLogWithStaticField.class, LoggerCustomLogWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerCustomLogWithStaticField() { + super(); + } +} class MyLoggerFactory { MyLoggerFactory() { super(); diff --git a/test/transform/resource/after-ecj/LoggerJBossLog.java b/test/transform/resource/after-ecj/LoggerJBossLog.java index e5c35708..c47f6c9e 100644 --- a/test/transform/resource/after-ecj/LoggerJBossLog.java +++ b/test/transform/resource/after-ecj/LoggerJBossLog.java @@ -35,4 +35,13 @@ class LoggerJBossLogOuter { LoggerJBossLogWithDifferentLoggerName() { super(); } +} +@JBossLog(topic = LoggerJBossLogWithStaticField.TOPIC) class LoggerJBossLogWithStaticField { + private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LoggerJBossLogWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerJBossLogWithStaticField() { + super(); + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerJul.java b/test/transform/resource/after-ecj/LoggerJul.java index 8aa4f59a..20cc5407 100644 --- a/test/transform/resource/after-ecj/LoggerJul.java +++ b/test/transform/resource/after-ecj/LoggerJul.java @@ -22,4 +22,13 @@ import lombok.extern.java.Log; LoggerJulWithDifferentName() { super(); } +} +@Log(topic = LoggerJulWithStaticField.TOPIC) class LoggerJulWithStaticField { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggerJulWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerJulWithStaticField() { + super(); + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerLog4j.java b/test/transform/resource/after-ecj/LoggerLog4j.java index 948412e2..e7d6c813 100644 --- a/test/transform/resource/after-ecj/LoggerLog4j.java +++ b/test/transform/resource/after-ecj/LoggerLog4j.java @@ -22,4 +22,13 @@ import lombok.extern.log4j.Log4j; LoggerLog4jWithDifferentName() { super(); } +} +@Log4j(topic = LoggerLog4jWithStaticField.TOPIC) class LoggerLog4jWithStaticField { + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LoggerLog4jWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerLog4jWithStaticField() { + super(); + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerLog4j2.java b/test/transform/resource/after-ecj/LoggerLog4j2.java index c2fcd428..88def98d 100644 --- a/test/transform/resource/after-ecj/LoggerLog4j2.java +++ b/test/transform/resource/after-ecj/LoggerLog4j2.java @@ -22,4 +22,13 @@ import lombok.extern.log4j.Log4j2; LoggerLog4j2WithDifferentName() { super(); } +} +@Log4j2(topic = LoggerLog4j2WithStaticField.TOPIC) class LoggerLog4j2WithStaticField { + private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LoggerLog4j2WithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerLog4j2WithStaticField() { + super(); + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4j.java b/test/transform/resource/after-ecj/LoggerSlf4j.java index 9c5405cb..c303a895 100644 --- a/test/transform/resource/after-ecj/LoggerSlf4j.java +++ b/test/transform/resource/after-ecj/LoggerSlf4j.java @@ -36,4 +36,31 @@ class LoggerSlf4jOuter { LoggerSlf4jWithDifferentLoggerName() { super(); } +} + +@Slf4j(topic = LoggerSlf4jWithStaticField.TOPIC) class LoggerSlf4jWithStaticField { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerSlf4jWithStaticField() { + super(); + } +} +@Slf4j(topic = (LoggerSlf4jWithTwoStaticFields.TOPIC + LoggerSlf4jWithTwoStaticFields.TOPIC)) class LoggerSlf4jWithTwoStaticFields { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger((LoggerSlf4jWithTwoStaticFields.TOPIC + LoggerSlf4jWithTwoStaticFields.TOPIC)); + static final String TOPIC = "StaticField"; + () { + } + LoggerSlf4jWithTwoStaticFields() { + super(); + } +} +@Slf4j(topic = ExtendedStringLiteral{AB}) class LoggerSlf4jWithTwoLiterals { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("AB"); + () { + } + LoggerSlf4jWithTwoLiterals() { + super(); + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4jInvalidTopic.java b/test/transform/resource/after-ecj/LoggerSlf4jInvalidTopic.java new file mode 100644 index 00000000..33e212e3 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jInvalidTopic.java @@ -0,0 +1,9 @@ +import lombok.extern.slf4j.Slf4j; +@Slf4j(topic = 42) class LoggerSlf4jWithIntegerTopic { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(42); + () { + } + LoggerSlf4jWithIntegerTopic() { + super(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerXSlf4j.java b/test/transform/resource/after-ecj/LoggerXSlf4j.java index 916859a4..04acdd77 100644 --- a/test/transform/resource/after-ecj/LoggerXSlf4j.java +++ b/test/transform/resource/after-ecj/LoggerXSlf4j.java @@ -22,4 +22,13 @@ import lombok.extern.slf4j.XSlf4j; LoggerXSlf4jWithDifferentName() { super(); } -} \ No newline at end of file +} +@XSlf4j(topic = LoggerXSlf4jWithStaticField.TOPIC) class LoggerXSlf4jWithStaticField { + private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LoggerXSlf4jWithStaticField.TOPIC); + static final String TOPIC = "StaticField"; + () { + } + LoggerXSlf4jWithStaticField() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SimpleTypeResolution.java b/test/transform/resource/after-ecj/SimpleTypeResolution.java index c413623e..d8321ca4 100644 --- a/test/transform/resource/after-ecj/SimpleTypeResolution.java +++ b/test/transform/resource/after-ecj/SimpleTypeResolution.java @@ -1,11 +1,13 @@ class SimpleTypeResolutionFail { private @Getter int x; SimpleTypeResolutionFail() { + super(); } } class SimpleTypeResolutionSuccess { private @lombok.Getter int x; SimpleTypeResolutionSuccess() { + super(); } public @java.lang.SuppressWarnings("all") int getX() { return this.x; diff --git a/test/transform/resource/after-ecj/SkipSuppressWarnings.java b/test/transform/resource/after-ecj/SkipSuppressWarnings.java new file mode 100644 index 00000000..53032519 --- /dev/null +++ b/test/transform/resource/after-ecj/SkipSuppressWarnings.java @@ -0,0 +1,27 @@ +class SkipSuppressWarnings { + private @lombok.Getter String field = ""; + private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference field2 = new java.util.concurrent.atomic.AtomicReference(); + SkipSuppressWarnings() { + super(); + } + public String getField() { + return this.field; + } + public @java.lang.SuppressWarnings({"unchecked"}) String getField2() { + java.lang.Object value = this.field2.get(); + if ((value == null)) + { + synchronized (this.field2) + { + value = this.field2.get(); + if ((value == null)) + { + final String actualValue = ""; + value = ((actualValue == null) ? this.field2 : actualValue); + this.field2.set(value); + } + } + } + return (String) ((value == this.field2) ? null : value); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index b47f318d..7902c95f 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -71,8 +71,8 @@ public class SuperBuilderBasic { return new SuperBuilderBasic.Parent.ParentBuilderImpl(); } } - public static @lombok.experimental.SuperBuilder class Child extends Parent { - public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder { + public static @lombok.experimental.SuperBuilder class Child extends SuperBuilderBasic.Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends SuperBuilderBasic.Parent.ParentBuilder { private @java.lang.SuppressWarnings("all") double field3; public ChildBuilder() { super(); diff --git a/test/transform/resource/after-ecj/SuperBuilderCustomized.java b/test/transform/resource/after-ecj/SuperBuilderCustomized.java index 32317f6a..fe0e1238 100644 --- a/test/transform/resource/after-ecj/SuperBuilderCustomized.java +++ b/test/transform/resource/after-ecj/SuperBuilderCustomized.java @@ -32,12 +32,14 @@ public class SuperBuilderCustomized { } } int field1; - protected @java.lang.SuppressWarnings("all") Parent(final SuperBuilderCustomized.Parent.ParentBuilder b) { + protected Parent(ParentBuilder b) { super(); + if ((b.field1 == 0)) + throw new IllegalArgumentException("field1 must be != 0"); this.field1 = b.field1; } - public static @java.lang.SuppressWarnings("all") SuperBuilderCustomized.Parent.ParentBuilder builder() { - return new SuperBuilderCustomized.Parent.ParentBuilderImpl(); + public static SuperBuilderCustomized.Parent.ParentBuilder builder(int field1) { + return new SuperBuilderCustomized.Parent.ParentBuilderImpl().field1(field1); } } public static @lombok.experimental.SuperBuilder class Child extends Parent { diff --git a/test/transform/resource/after-ecj/TypeUseAnnotations.java b/test/transform/resource/after-ecj/TypeUseAnnotations.java index 156643b9..7041b59e 100644 --- a/test/transform/resource/after-ecj/TypeUseAnnotations.java +++ b/test/transform/resource/after-ecj/TypeUseAnnotations.java @@ -5,11 +5,20 @@ import java.util.List; int x(); } class TypeUseAnnotations { + class Inner { + Inner() { + super(); + } + } @lombok.Getter List<@TA(x = 5) String> foo; + @lombok.Getter List bar; TypeUseAnnotations() { super(); } public @java.lang.SuppressWarnings("all") List<@TA(x = 5) String> getFoo() { return this.foo; } + public @java.lang.SuppressWarnings("all") List getBar() { + return this.bar; + } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValLambda.java b/test/transform/resource/after-ecj/ValLambda.java index 5b52869f..6b59bdbd 100644 --- a/test/transform/resource/after-ecj/ValLambda.java +++ b/test/transform/resource/after-ecj/ValLambda.java @@ -1,3 +1,5 @@ +import java.io.Serializable; + class ValLambda { static { final @lombok.val java.lang.Runnable foo = ((System.currentTimeMillis() > 0) ? (Runnable) () -> { @@ -16,8 +18,8 @@ class ValLambda { final @lombok.val java.lang.Runnable foo = (Runnable) () -> { }; } - public void easyIntersectionLambda() { - final @lombok.val java.lang.Runnable foo = (Runnable & java.io.Serializable) () -> { + public void intersectionLambda() { + final @lombok.val java.io.Serializable foo = (Runnable & Serializable) () -> { }; final @lombok.val java.io.Serializable bar = (java.io.Serializable & Runnable) () -> { }; diff --git a/test/transform/resource/after-ecj/ValueStaticConstructorOf.java b/test/transform/resource/after-ecj/ValueStaticConstructorOf.java index 6cf71ed4..87883566 100644 --- a/test/transform/resource/after-ecj/ValueStaticConstructorOf.java +++ b/test/transform/resource/after-ecj/ValueStaticConstructorOf.java @@ -19,23 +19,23 @@ public final @Value(staticConstructor = "of") class ValueStaticConstructorOf { if ((! (o instanceof ValueStaticConstructorOf))) return false; final ValueStaticConstructorOf other = (ValueStaticConstructorOf) o; - final java.lang.Object this$name = this.getName(); - final java.lang.Object other$name = other.getName(); - if (((this$name == null) ? (other$name != null) : (! this$name.equals(other$name)))) - return false; final java.lang.Object this$price = this.getPrice(); final java.lang.Object other$price = other.getPrice(); if (((this$price == null) ? (other$price != null) : (! this$price.equals(other$price)))) return false; + final java.lang.Object this$name = this.getName(); + final java.lang.Object other$name = other.getName(); + if (((this$name == null) ? (other$name != null) : (! this$name.equals(other$name)))) + return false; return true; } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 59; int result = 1; - final java.lang.Object $name = this.getName(); - result = ((result * PRIME) + (($name == null) ? 43 : $name.hashCode())); final java.lang.Object $price = this.getPrice(); result = ((result * PRIME) + (($price == null) ? 43 : $price.hashCode())); + final java.lang.Object $name = this.getName(); + result = ((result * PRIME) + (($name == null) ? 43 : $name.hashCode())); return result; } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { @@ -44,4 +44,4 @@ public final @Value(staticConstructor = "of") class ValueStaticConstructorOf { public static @java.lang.SuppressWarnings("all") ValueStaticConstructorOf of(final String name, final Double price) { return new ValueStaticConstructorOf(name, price); } -} \ No newline at end of file +} diff --git a/test/transform/resource/before/BuilderConstructorJavadoc.java b/test/transform/resource/before/BuilderConstructorJavadoc.java new file mode 100644 index 00000000..ebbd473f --- /dev/null +++ b/test/transform/resource/before/BuilderConstructorJavadoc.java @@ -0,0 +1,35 @@ +import java.util.List; + +class BuilderConstructorJavadoc { + /** + * This is a comment + * + * @param basic tag is moved to the setter + * @param multiline a param comment + * can be on multiple lines and can use + * {@code @code} or tags + * @param predef don't copy this one + * @param predefWithJavadoc don't copy this one + */ + @lombok.Builder + BuilderConstructorJavadoc(int basic, int multiline, int predef, int predefWithJavadoc) { + + } + + public static class BuilderConstructorJavadocBuilder { + public BuilderConstructorJavadocBuilder predef(final int x) { + this.predef = x; + return this; + } + + /** + * This javadoc remains untouched. + * @param x 1/100 of the thing + * @return the updated builder + */ + public BuilderConstructorJavadocBuilder predefWithJavadoc(final int x) { + this.predefWithJavadoc = x; + return this; + } + } +} diff --git a/test/transform/resource/before/CheckerFrameworkSuperBuilder.java b/test/transform/resource/before/CheckerFrameworkSuperBuilder.java index 54aefb37..ed9e14cb 100644 --- a/test/transform/resource/before/CheckerFrameworkSuperBuilder.java +++ b/test/transform/resource/before/CheckerFrameworkSuperBuilder.java @@ -12,7 +12,7 @@ class CheckerFrameworkSuperBuilder { } @lombok.experimental.SuperBuilder - public static class Child extends Parent { + public static class ZChild extends Parent { @lombok.Builder.Default int a = 1; int b; } diff --git a/test/transform/resource/before/DelegateAlreadyImplemented.java b/test/transform/resource/before/DelegateAlreadyImplemented.java new file mode 100644 index 00000000..c43c1949 --- /dev/null +++ b/test/transform/resource/before/DelegateAlreadyImplemented.java @@ -0,0 +1,45 @@ +public class DelegateAlreadyImplemented { + + @lombok.experimental.Delegate + private A a; + + public void a() { + } + + public void b(java.util.List l) { + } + + public void c(java.util.List l, String[] a, Integer... varargs) { + } + + public void d(String[][][][] d) { + } + + public void e(Y x) { + } + + @SuppressWarnings("unchecked") + public void f(T s, java.util.List l, T[] a, T... varargs) { + } + + public void g(Number g) { + } +} + +interface A { + public void a(); + + public void b(java.util.List l); + + @SuppressWarnings("unchecked") + public void c(java.util.List l, String[] a, T... varargs); + + public void d(String[][][][] d); + + public X e(X x); + + @SuppressWarnings("unchecked") + public void f(T2 s, java.util.List l, T2[] a, T2... varargs); + + public void g(G g); +} \ No newline at end of file diff --git a/test/transform/resource/before/DelegateGenerics.java b/test/transform/resource/before/DelegateGenerics.java new file mode 100644 index 00000000..e89158a9 --- /dev/null +++ b/test/transform/resource/before/DelegateGenerics.java @@ -0,0 +1,14 @@ +public class DelegateGenerics { + @lombok.experimental.Delegate + I1 target; +} + +interface I1 extends I2 { +} +interface I2 extends I3 { +} +interface I3 { + public T t(T t); + public I i(I a); + public A a(A a); +} \ No newline at end of file diff --git a/test/transform/resource/before/DelegateWithVarargs2.java b/test/transform/resource/before/DelegateWithVarargs2.java new file mode 100644 index 00000000..8a3dbf14 --- /dev/null +++ b/test/transform/resource/before/DelegateWithVarargs2.java @@ -0,0 +1,9 @@ +import lombok.experimental.Delegate; + +class DelegateWithVarargs2 { + @Delegate private DelegateWithVarargs2.B bar; + + public class B { + public void varargs(Object[]... keys) {} + } +} diff --git a/test/transform/resource/before/EqualsAndHashCodeRank.java b/test/transform/resource/before/EqualsAndHashCodeRank.java new file mode 100644 index 00000000..5dda54f8 --- /dev/null +++ b/test/transform/resource/before/EqualsAndHashCodeRank.java @@ -0,0 +1,7 @@ +import lombok.EqualsAndHashCode; +@EqualsAndHashCode +public class EqualsAndHashCodeRank { + @EqualsAndHashCode.Include int a; + @EqualsAndHashCode.Include(rank = 10) int b; + @EqualsAndHashCode.Include int c; +} diff --git a/test/transform/resource/before/GetterLazyArguments.java b/test/transform/resource/before/GetterLazyArguments.java new file mode 100644 index 00000000..47dfae55 --- /dev/null +++ b/test/transform/resource/before/GetterLazyArguments.java @@ -0,0 +1,21 @@ +// version 8: +class GetterLazyArguments { + static String fun() { return null; } + static String stringInt(String arg1, Integer arg2) { return null; } + static String stringRunnable(String arg1, Runnable arg2) { return null; } + + @lombok.Getter(lazy=true) + private final String field1 = stringInt(("a"), (1)); + + @lombok.Getter(lazy=true) + private final String field2 = stringInt(true ? "a" : "b", true ? 1 : 0); + + @lombok.Getter(lazy=true) + private final String field3 = stringInt(("a"), true ? 1 : 0); + + @lombok.Getter(lazy=true) + private final String field4 = stringRunnable(fun(), () -> { }); + + @lombok.Getter(lazy=true) + private final String field5 = stringRunnable(("a"), () -> { }); +} diff --git a/test/transform/resource/before/JacksonBuilderSingular.java b/test/transform/resource/before/JacksonBuilderSingular.java new file mode 100644 index 00000000..c179c760 --- /dev/null +++ b/test/transform/resource/before/JacksonBuilderSingular.java @@ -0,0 +1,31 @@ +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import lombok.Builder; +import lombok.Singular; +import lombok.extern.jackson.Jacksonized; + +@Jacksonized +@Builder +public class JacksonBuilderSingular { + @JsonAnySetter + @Singular("any") + private Map any; + + @JsonProperty("v_a_l_u_e_s") + @Singular + private List values; + + @JsonAnySetter + @Singular("guavaAny") + private ImmutableMap guavaAny; + + @JsonProperty("guava_v_a_l_u_e_s") + @Singular + private ImmutableList guavaValues; +} diff --git a/test/transform/resource/before/LoggerCommons.java b/test/transform/resource/before/LoggerCommons.java index 00419d00..e209c1d0 100644 --- a/test/transform/resource/before/LoggerCommons.java +++ b/test/transform/resource/before/LoggerCommons.java @@ -11,3 +11,8 @@ class LoggerCommonsWithImport { @CommonsLog(topic="DifferentName") class LoggerCommonsWithDifferentName { } + +@CommonsLog(topic=LoggerCommonsWithStaticField.TOPIC) +class LoggerCommonsWithStaticField { + static final String TOPIC = "StaticField"; +} \ No newline at end of file diff --git a/test/transform/resource/before/LoggerCustomWithTopicAndName.java b/test/transform/resource/before/LoggerCustomWithTopicAndName.java index b40ed86a..5b803217 100644 --- a/test/transform/resource/before/LoggerCustomWithTopicAndName.java +++ b/test/transform/resource/before/LoggerCustomWithTopicAndName.java @@ -3,6 +3,11 @@ class LoggerCustomLog { } +@lombok.CustomLog(topic=LoggerCustomLogWithStaticField.TOPIC) +class LoggerCustomLogWithStaticField { + static final String TOPIC = "StaticField"; +} + class MyLoggerFactory { static MyLoggerFactory create(String name, String t1, Object o, Class clazz, String t2) { return null; diff --git a/test/transform/resource/before/LoggerJBossLog.java b/test/transform/resource/before/LoggerJBossLog.java index fbd88177..f3480867 100644 --- a/test/transform/resource/before/LoggerJBossLog.java +++ b/test/transform/resource/before/LoggerJBossLog.java @@ -17,4 +17,9 @@ class LoggerJBossLogOuter { @JBossLog(topic="DifferentLogger") class LoggerJBossLogWithDifferentLoggerName { +} + +@JBossLog(topic=LoggerJBossLogWithStaticField.TOPIC) +class LoggerJBossLogWithStaticField { + static final String TOPIC = "StaticField"; } \ No newline at end of file diff --git a/test/transform/resource/before/LoggerJul.java b/test/transform/resource/before/LoggerJul.java index 006cc344..7b10d015 100644 --- a/test/transform/resource/before/LoggerJul.java +++ b/test/transform/resource/before/LoggerJul.java @@ -10,4 +10,9 @@ class LoggerJulWithImport { @Log(topic="DifferentName") class LoggerJulWithDifferentName { +} + +@Log(topic=LoggerJulWithStaticField.TOPIC) +class LoggerJulWithStaticField { + static final String TOPIC = "StaticField"; } \ No newline at end of file diff --git a/test/transform/resource/before/LoggerLog4j.java b/test/transform/resource/before/LoggerLog4j.java index 351049c5..b7086a05 100644 --- a/test/transform/resource/before/LoggerLog4j.java +++ b/test/transform/resource/before/LoggerLog4j.java @@ -10,4 +10,9 @@ class LoggerLog4jWithImport { @Log4j(topic="DifferentName") class LoggerLog4jWithDifferentName { +} + +@Log4j(topic=LoggerLog4jWithStaticField.TOPIC) +class LoggerLog4jWithStaticField { + static final String TOPIC = "StaticField"; } \ No newline at end of file diff --git a/test/transform/resource/before/LoggerLog4j2.java b/test/transform/resource/before/LoggerLog4j2.java index c9cf9412..10b3aae5 100644 --- a/test/transform/resource/before/LoggerLog4j2.java +++ b/test/transform/resource/before/LoggerLog4j2.java @@ -10,4 +10,9 @@ class LoggerLog4j2WithImport { @Log4j2(topic="DifferentName") class LoggerLog4j2WithDifferentName { +} + +@Log4j2(topic=LoggerLog4j2WithStaticField.TOPIC) +class LoggerLog4j2WithStaticField { + static final String TOPIC = "StaticField"; } \ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4j.java b/test/transform/resource/before/LoggerSlf4j.java index 1113a63e..3f8284e8 100644 --- a/test/transform/resource/before/LoggerSlf4j.java +++ b/test/transform/resource/before/LoggerSlf4j.java @@ -17,4 +17,18 @@ class LoggerSlf4jOuter { @Slf4j(topic="DifferentLogger") class LoggerSlf4jWithDifferentLoggerName { +} + +@Slf4j(topic=LoggerSlf4jWithStaticField.TOPIC) +class LoggerSlf4jWithStaticField { + static final String TOPIC = "StaticField"; +} + +@Slf4j(topic=LoggerSlf4jWithTwoStaticFields.TOPIC + LoggerSlf4jWithTwoStaticFields.TOPIC) +class LoggerSlf4jWithTwoStaticFields { + static final String TOPIC = "StaticField"; +} + +@Slf4j(topic="A"+"B") +class LoggerSlf4jWithTwoLiterals { } \ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4jInvalidTopic.java b/test/transform/resource/before/LoggerSlf4jInvalidTopic.java new file mode 100644 index 00000000..eed02f01 --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jInvalidTopic.java @@ -0,0 +1,5 @@ +import lombok.extern.slf4j.Slf4j; + +@Slf4j(topic=42) +class LoggerSlf4jWithIntegerTopic { +} \ No newline at end of file diff --git a/test/transform/resource/before/LoggerXSlf4j.java b/test/transform/resource/before/LoggerXSlf4j.java index a8bcb0c3..f70f2e2d 100644 --- a/test/transform/resource/before/LoggerXSlf4j.java +++ b/test/transform/resource/before/LoggerXSlf4j.java @@ -10,4 +10,9 @@ class LoggerXSlf4jWithImport { @XSlf4j(topic="DifferentName") class LoggerXSlf4jWithDifferentName { +} + +@XSlf4j(topic=LoggerXSlf4jWithStaticField.TOPIC) +class LoggerXSlf4jWithStaticField { + static final String TOPIC = "StaticField"; } \ No newline at end of file diff --git a/test/transform/resource/before/SkipSuppressWarnings.java b/test/transform/resource/before/SkipSuppressWarnings.java new file mode 100644 index 00000000..ed36eeb9 --- /dev/null +++ b/test/transform/resource/before/SkipSuppressWarnings.java @@ -0,0 +1,9 @@ +//CONF: lombok.addSuppressWarnings = false + +class SkipSuppressWarnings { + @lombok.Getter + private String field = ""; + + @lombok.Getter(lazy=true) + private final String field2 = ""; +} \ No newline at end of file diff --git a/test/transform/resource/before/SuperBuilderBasic.java b/test/transform/resource/before/SuperBuilderBasic.java index f4e8c670..99d7284e 100644 --- a/test/transform/resource/before/SuperBuilderBasic.java +++ b/test/transform/resource/before/SuperBuilderBasic.java @@ -8,7 +8,7 @@ public class SuperBuilderBasic { } @lombok.experimental.SuperBuilder - public static class Child extends Parent { + public static class Child extends SuperBuilderBasic.Parent { double field3; } diff --git a/test/transform/resource/before/SuperBuilderCustomized.java b/test/transform/resource/before/SuperBuilderCustomized.java index 77830587..8e641d90 100644 --- a/test/transform/resource/before/SuperBuilderCustomized.java +++ b/test/transform/resource/before/SuperBuilderCustomized.java @@ -14,6 +14,16 @@ public class SuperBuilderCustomized { } } int field1; + + protected Parent(ParentBuilder b) { + if (b.field1 == 0) + throw new IllegalArgumentException("field1 must be != 0"); + this.field1 = b.field1; + } + + public static SuperBuilderCustomized.Parent.ParentBuilder builder(int field1) { + return new SuperBuilderCustomized.Parent.ParentBuilderImpl().field1(field1); + } } @lombok.experimental.SuperBuilder diff --git a/test/transform/resource/before/TypeUseAnnotations.java b/test/transform/resource/before/TypeUseAnnotations.java index c09a291d..7175930f 100644 --- a/test/transform/resource/before/TypeUseAnnotations.java +++ b/test/transform/resource/before/TypeUseAnnotations.java @@ -8,4 +8,6 @@ import java.util.List; } class TypeUseAnnotations { @lombok.Getter List<@TA(x=5) String> foo; + @lombok.Getter List bar; + class Inner { } } diff --git a/test/transform/resource/before/ValLambda.java b/test/transform/resource/before/ValLambda.java index 5c9c4a43..e956bcd3 100644 --- a/test/transform/resource/before/ValLambda.java +++ b/test/transform/resource/before/ValLambda.java @@ -1,4 +1,6 @@ // version 8: +import java.io.Serializable; + class ValLambda { static { @@ -12,8 +14,8 @@ class ValLambda { lombok.val foo = (Runnable)()-> {}; } - public void easyIntersectionLambda() { - lombok.val foo = (Runnable & java.io.Serializable)()-> {}; + public void intersectionLambda() { + lombok.val foo = (Runnable & Serializable)()-> {}; lombok.val bar = (java.io.Serializable & Runnable)()-> {}; } diff --git a/test/transform/resource/before/ValLub.java b/test/transform/resource/before/ValLub.java index c1b41c26..509a4f8b 100644 --- a/test/transform/resource/before/ValLub.java +++ b/test/transform/resource/before/ValLub.java @@ -1,21 +1,21 @@ class ValLub { public void easyLub() { java.util.Map m = java.util.Collections.emptyMap(); - + lombok.val foo = (System.currentTimeMillis() > 0) ? m : java.util.Collections.emptyMap(); } - + public void sillyLubWithUnboxingThatProducesErrorThatVarIsPrimitive() { Integer i = 20; Double d = 20.0; - + lombok.val thisShouldBePrimitiveDouble = (System.currentTimeMillis() > 0) ? i : d; } - + public void hardLub() { java.util.List list = new java.util.ArrayList(); java.util.Set set = new java.util.HashSet(); - + lombok.val thisShouldBeCollection = (System.currentTimeMillis() > 0) ? list : set; thisShouldBeCollection.add(""); String foo = thisShouldBeCollection.iterator().next(); diff --git a/test/transform/resource/messages-delombok/LoggerSlf4jInvalidTopic.java.messages b/test/transform/resource/messages-delombok/LoggerSlf4jInvalidTopic.java.messages new file mode 100644 index 00000000..8de0a120 --- /dev/null +++ b/test/transform/resource/messages-delombok/LoggerSlf4jInvalidTopic.java.messages @@ -0,0 +1,2 @@ +3 incompatible types: int cannot be converted to java.lang.String +-1 not flagged modified \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages b/test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages index 9bfcba0c..8cc7fb58 100644 --- a/test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages +++ b/test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages @@ -1 +1 @@ -8 org.checkerframework cannot be resolved to a type +6 org.checkerframework.common cannot be resolved to a type diff --git a/test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages b/test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages index d385a95c..8cc7fb58 100644 --- a/test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages +++ b/test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages @@ -1 +1 @@ -6 org.checkerframework cannot be resolved to a type +6 org.checkerframework.common cannot be resolved to a type diff --git a/test/transform/resource/messages-ecj/LoggerSlf4jInvalidTopic.java.messages b/test/transform/resource/messages-ecj/LoggerSlf4jInvalidTopic.java.messages new file mode 100644 index 00000000..9bc2a82b --- /dev/null +++ b/test/transform/resource/messages-ecj/LoggerSlf4jInvalidTopic.java.messages @@ -0,0 +1 @@ +3 Type mismatch: cannot convert from int to String \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/SkipSuppressWarnings.java.messages b/test/transform/resource/messages-ecj/SkipSuppressWarnings.java.messages new file mode 100644 index 00000000..5e7d759c --- /dev/null +++ b/test/transform/resource/messages-ecj/SkipSuppressWarnings.java.messages @@ -0,0 +1 @@ +7 Unnecessary @SuppressWarnings("unchecked") \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/ValLambda.java.messages b/test/transform/resource/messages-ecj/ValLambda.java.messages index e6940434..fa7231ef 100644 --- a/test/transform/resource/messages-ecj/ValLambda.java.messages +++ b/test/transform/resource/messages-ecj/ValLambda.java.messages @@ -1,2 +1,2 @@ -23 Function is a raw type. References to generic type Function should be parameterized -24 Function is a raw type. References to generic type Function should be parameterized \ No newline at end of file +24 Function is a raw type. References to generic type Function should be parameterized +25 Function is a raw type. References to generic type Function should be parameterized \ No newline at end of file diff --git a/test/transform/resource/messages-idempotent/LoggerSlf4jInvalidTopic.java.messages b/test/transform/resource/messages-idempotent/LoggerSlf4jInvalidTopic.java.messages new file mode 100644 index 00000000..d894fad1 --- /dev/null +++ b/test/transform/resource/messages-idempotent/LoggerSlf4jInvalidTopic.java.messages @@ -0,0 +1 @@ +3 incompatible types: int cannot be converted to java.lang.String \ No newline at end of file diff --git a/website/resources/img/eclipse-p2-step1.png b/website/resources/img/eclipse-p2-step1.png new file mode 100644 index 00000000..92cdef86 Binary files /dev/null and b/website/resources/img/eclipse-p2-step1.png differ diff --git a/website/resources/img/eclipse-p2-step2.png b/website/resources/img/eclipse-p2-step2.png new file mode 100644 index 00000000..84139ad8 Binary files /dev/null and b/website/resources/img/eclipse-p2-step2.png differ diff --git a/website/templates/all-versions.html b/website/templates/all-versions.html index 0207b351..db48f664 100644 --- a/website/templates/all-versions.html +++ b/website/templates/all-versions.html @@ -6,9 +6,7 @@

diff --git a/website/templates/features/Builder.html b/website/templates/features/Builder.html index f9897d03..1b6c6e62 100644 --- a/website/templates/features/Builder.html +++ b/website/templates/features/Builder.html @@ -132,7 +132,7 @@

- If your identifiers are written in common english, lombok assumes that the name of any collection with @Singular on it is an english plural and will attempt to automatically singularize that name. If this is possible, the add-one method will use this name. For example, if your collection is called statuses, then the add-one method will automatically be called status. You can also specify the singular form of your identifier explictly by passing the singular form as argument to the annotation like so: @Singular("axis") List<Line> axes;.
+ If your identifiers are written in common english, lombok assumes that the name of any collection with @Singular on it is an english plural and will attempt to automatically singularize that name. If this is possible, the add-one method will use this name. For example, if your collection is called statuses, then the add-one method will automatically be called status. You can also specify the singular form of your identifier explicitly by passing the singular form as argument to the annotation like so: @Singular("axis") List<Line> axes;.
If lombok cannot singularize your identifier, or it is ambiguous, lombok will generate an error and force you to explicitly specify the singular name.

The snippet below does not show what lombok generates for a @Singular field/parameter because it is rather complicated. You can view a snippet here. diff --git a/website/templates/features/configuration.html b/website/templates/features/configuration.html index fa6d6371..16214d4e 100644 --- a/website/templates/features/configuration.html +++ b/website/templates/features/configuration.html @@ -100,6 +100,11 @@

  1. lombok.extern.findbugs.addSuppressFBWarnings = true
+

+ Lombok adds the @SuppressWarnings("all") annotation to all generated nodes by default. This can be turned off which is useful if you want to use static code analyzers like Checker Framework. +

    +
  1. lombok.addSuppressWarnings = false
  2. +

diff --git a/website/templates/features/experimental/SuperBuilder.html b/website/templates/features/experimental/SuperBuilder.html index c929e8f5..e9a0958d 100644 --- a/website/templates/features/experimental/SuperBuilder.html +++ b/website/templates/features/experimental/SuperBuilder.html @@ -6,6 +6,8 @@ @SuperBuilder was introduced as experimental feature in lombok v1.18.2.

@SuperBuilder's toBuilder feature and limited support for customization was added with lombok v1.18.4. +

+ @SuperBuilder customization possibilities were extended with lombok v1.18.14.

@@ -13,7 +15,7 @@

The @SuperBuilder annotation produces complex builder APIs for your classes. In contrast to @Builder, @SuperBuilder also works with fields from superclasses. - However, it only works for types, and customization possibilities are limited. + However, it only works for types. Most importantly, it requires that all superclasses also have the @SuperBuilder annotation.

@SuperBuilder lets you automatically produce the code required to have your class be instantiable with code such as:
@@ -21,7 +23,7 @@

@SuperBuilder can generate so-called 'singular' methods for collection parameters/fields. For details, see the @Singular documentation in @Builder.

- @SuperBuilder generates a private constructor on the class that takes a builder instance as a parameter. This constructor sets the fields of the new instance to the values from the builder. + @SuperBuilder generates a protected constructor on the class that takes a builder instance as a parameter. This constructor sets the fields of the new instance to the values from the builder.

@SuperBuilder is not compatible with @Builder.

@@ -32,8 +34,9 @@

To ensure type-safety, @SuperBuilder generates two inner builder classes for each annotated class, one abstract and one concrete class named FoobarBuilder and FoobarBuilderImpl (where Foobar is the name of the annotated class).

- Customizing the code generated by @SuperBuilder is limited to adding new methods or annotations to the builder classes, and providing custom implementations of the 'set', builder(), and build() methods. - You have to make sure that the builder class declaration headers match those that would have been generated by lombok. Due to the heavy generics usage, we strongly advice to copy the builder class definition header from the uncustomized delomboked code. + You can customize most of the code generated by @SuperBuilder, except for internal methods (e.g. self()). + You have to make sure that the builder class declaration headers match those that would have been generated by lombok. + Due to the heavy generics usage, we strongly advice to take the uncustomized delomboked code as a reference when customizing @SuperBuilder.

The configurable aspects of builder are:

    diff --git a/website/templates/setup/eclipse.html b/website/templates/setup/eclipse.html index 85304c83..d9621501 100644 --- a/website/templates/setup/eclipse.html +++ b/website/templates/setup/eclipse.html @@ -23,4 +23,16 @@

    + <@s.section title="Via eclipse plugin installer"> + WARNING: This plugin installer is currently unsigned, and we have given up on figuring out how to fix that; if team eclipse or somebody else can help us out, we're all ears! +

    + You can install lombok directly from within eclipse, and in that way, you can also include lombok as part of your team eclipse deployment configuration. To do this, use + update site https://projectlombok.org/p2:
    +
    +
    +
    +
    + +

    + diff --git a/website/templates/setup/kobalt.html b/website/templates/setup/kobalt.html index 26adf23d..beb60d8c 100644 --- a/website/templates/setup/kobalt.html +++ b/website/templates/setup/kobalt.html @@ -3,7 +3,7 @@ <@s.scaffold title="Kobalt"> <@s.introduction>

    - To set up lombok with any build tool, you have to specify that the lombok dependency is required to compile your source code, but does not need to be present when running/testing/jarring/otherwise deploying your code. Generally this is called a 'provided' dependency. This page explains how to integrate lombok with the Kobalt buid tool. + To set up lombok with any build tool, you have to specify that the lombok dependency is required to compile your source code, but does not need to be present when running/testing/jarring/otherwise deploying your code. Generally this is called a 'provided' dependency. This page explains how to integrate lombok with the Kobalt build tool.

    Lombok is available in maven central, so telling Kobalt to download lombok is easy.