diff --git a/.github/workflows/ant.yml b/.github/workflows/ant.yml index 07a77430..278f9752 100644 --- a/.github/workflows/ant.yml +++ b/.github/workflows/ant.yml @@ -10,16 +10,16 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 11 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 11 - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ivyCache @@ -31,7 +31,7 @@ jobs: - name: Build with Ant run: ant -noinput dist - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: lombok.jar path: dist/lombok.jar @@ -40,9 +40,11 @@ jobs: test-javac: runs-on: ubuntu-latest needs: build + env: + EA_JDK: 22 strategy: matrix: - jdk: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21] + jdk: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22] goal: [javacCurrent] include: - jdk: 11 @@ -53,32 +55,34 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.jdk }} - if: ${{ matrix.jdk != 21 }} - uses: actions/setup-java@v3 + if: ${{ matrix.jdk < env.EA_JDK }} + uses: actions/setup-java@v4 with: java-version: ${{ matrix.jdk }} distribution: 'zulu' - - name: Set up JDK 21-ea - if: ${{ matrix.jdk == 21 }} + - name: Set up JDK ${{ matrix.jdk }} Early Access release + if: ${{ matrix.jdk >= env.EA_JDK }} uses: oracle-actions/setup-java@v1 with: website: jdk.java.net - release: 21 + release: ${{ matrix.jdk }} version: latest - name: Install Ant + env: + ANT_VERSION: 1.10.14 run: | - wget https://archive.apache.org/dist/ant/binaries/apache-ant-1.10.13-bin.zip - unzip apache-ant-1.10.13-bin.zip -d "${HOME}" - echo "ANT_HOME=${HOME}/apache-ant-1.10.13" >> $GITHUB_ENV - echo "${HOME}/apache-ant-1.10.13/bin" >> $GITHUB_PATH + wget https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.zip + unzip apache-ant-$ANT_VERSION-bin.zip -d "${HOME}" + echo "ANT_HOME=${HOME}/apache-ant-$ANT_VERSION" >> $GITHUB_ENV + echo "${HOME}/apache-ant-$ANT_VERSION/bin" >> $GITHUB_PATH - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ivyCache @@ -101,9 +105,15 @@ jobs: - eclipse-202006-jdk8 - eclipse-202212 - eclipse-202309 + - eclipse-202312 + - eclipse-202403 + - eclipse-I-build - eclipse-oxygen-full - eclipse-2022-03-full - eclipse-2023-09-full + - eclipse-2023-12-full + - eclipse-2024-03-full + - eclipse-I-build-full - ecj11 - ecj14 - ecj16 @@ -112,16 +122,16 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 17 distribution: 'zulu' - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ivyCache @@ -132,7 +142,7 @@ jobs: - name: Cache base testenv if: ${{ !endsWith(matrix.version, 'full') }} - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | testenv @@ -140,7 +150,7 @@ jobs: - name: Cache full testenv if: ${{ endsWith(matrix.version, 'full') }} - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | testenv @@ -154,21 +164,23 @@ jobs: needs: build strategy: matrix: - jdk: [8, 11, 17, 21] + jdk: [8, 11, 17, 21, 22] tool: - {name: "maven", cmd: "mvn compile"} - {name: "gradle", cmd: "gradle assemble"} - {name: "ant", cmd: "ant dist"} - {name: "bazel", cmd: "bazel build //:ProjectRunner"} + exclude: + - {tool: {name: "gradle", cmd: "gradle assemble"}, jdk: 22} fail-fast: false env: IMAGE_NAME: lombok-${{ matrix.tool.name }}-jdk${{ matrix.jdk }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: lombok.jar diff --git a/AUTHORS b/AUTHORS index 167451d8..a8c9bcc4 100755 --- a/AUTHORS +++ b/AUTHORS @@ -17,6 +17,7 @@ Denis Stepanov Emil Lundberg Enrique da Costa Cambio Jacob Middag +James Yoo Jan Matèrne Jan Rieke Jappe van der Hel @@ -26,6 +27,7 @@ Kevin Chirls Liu DongMiao Luan Nico Maarten Mulders +Manu Sridharan Mark Haynes Mart Hagenaars Martin O'Connor <38929043+martinoconnor@users.noreply.github.com> @@ -34,6 +36,7 @@ Mateusz Matela Michael Dardis Michael Ernst Michiel Verheul +Ole Ludwig Pascal Bihler Peter Grant Philipp Eichhorn @@ -42,6 +45,7 @@ Pim van der Loos Rabea Gransberger Raul Wißfeld Reinier Zwitserloot +Rob Stryker Robbert Jan Grootjans Robert Wertman Roel Spilker diff --git a/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.46.xml b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.50.xml similarity index 87% rename from buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.46.xml rename to buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.50.xml index 37de93e6..e6af2118 100644 --- a/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.46.xml +++ b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.50.xml @@ -1,5 +1,5 @@ - + @@ -9,6 +9,6 @@ - + diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml index b165300b..c3687cb8 100644 --- a/buildScripts/ivy.xml +++ b/buildScripts/ivy.xml @@ -32,12 +32,14 @@ + + - + @@ -64,6 +66,7 @@ + @@ -74,7 +77,7 @@ - + @@ -132,6 +135,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildScripts/setup.ant.xml b/buildScripts/setup.ant.xml index 39954a02..2a25a9ba 100644 --- a/buildScripts/setup.ant.xml +++ b/buildScripts/setup.ant.xml @@ -45,25 +45,22 @@ This buildfile is part of projectlombok.org. It sets up the build itself. - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - Full eclipse testing requires downloading a native SWT binding. This script knows how to download for OS = [mac, linux, or windows] and architecture = [aarch64 or x86-64]. You have something different, you unique snowflake you. Your OS: "${os.name}", Your arch: "${os.arch}". + Full eclipse testing requires downloading a native SWT binding. This script knows how to download for OS = [mac, linux, or windows] and architecture = [aarch64 or x86-64]. You have something different, you unique snowflake you. Your OS: "${os.name}", Your arch: "${os.arch}". @@ -118,7 +115,7 @@ This buildfile is part of projectlombok.org. It sets up the build itself. - + @@ -160,15 +157,27 @@ This buildfile is part of projectlombok.org. It sets up the build itself. - + - + - + + + + + + + + + + + + + @@ -192,13 +201,29 @@ This buildfile is part of projectlombok.org. It sets up the build itself. - - - - + + + + + + + + + + + + + + + + + + + + @@ -206,133 +231,9 @@ This buildfile is part of projectlombok.org. It sets up the build itself. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/buildScripts/tests.ant.xml b/buildScripts/tests.ant.xml index c7f7a865..8f7023db 100644 --- a/buildScripts/tests.ant.xml +++ b/buildScripts/tests.ant.xml @@ -218,6 +218,41 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -261,6 +296,18 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn + + + + + + + + + + + + diff --git a/doc/changelog.markdown b/doc/changelog.markdown index d93eb9d4..7303de17 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,10 +1,22 @@ Lombok Changelog ---------------- -### v1.18.31 "Edgy Guinea Pig" +### v1.18.33 "Edgy Guinea Pig" +* We recently released v1.18.32; there is no edge release since then. + +### v1.18.32 (March 20th, 2024) +* PLATFORM: Initial JDK22 support added. +* PLAFTORM Added support for Eclipse 2024-03. [Issue #3620](https://github.com/projectlombok/lombok/issues/3620). +* PLATFORM: Added support for recent versions of eclipse (released Q4 2023 or later or so) which would cause failures in the eclipse logs such as `java.lang.NoSuchMethodError: 'java.lang.StringBuffer org.eclipse.jdt…`. [Issue #3564](https://github.com/projectlombok/lombok/issues/3564). * FEATURE: `@Locked` has been introduced. Like `@Synchronized` but with `java.util.concurrent.locks` locks instead of the `synchronized` primitive. Thanks, Pim van der Loos for the PR! [Issue #3506](https://github.com/projectlombok/lombok/issues/3506). -* BUGFIX: Eclipse projects using the com.pro-crafting.tools:jasperreports-plugin will now compile -* We recently released v1.18.30; there is no edge release since then. +* NECROMANCY: Inlining a generated getter in eclipse would result in eclipse incorrectly replacing calls with `@Getter` instead of the actual field's name. [Issue #562](https://github.com/projectlombok/lombok/issues/562). This issue is almost old enough to drink. Points for dedication go to Rawi for fixing this one. +* BUGFIX: When `@SuperBuilder` was used on a type with an annotated generic type, it would error `wrong number of type arguments`. [Issue #3592](https://github.com/projectlombok/lombok/issues/3592). +* BUGFIX: It was possible to create an infinite build loop using `@ExtensionMethod`. [Issue #3225](https://github.com/projectlombok/lombok/issues/3225). +* BUGFIX: Using `@Getter(lazy=true)` would fail if the expression contained a variable called `value`. [Issue #2917](https://github.com/projectlombok/lombok/issues/2917). +* BUGFIX: Many lombok features wouldn't work properly on records contained within an outer type unless you explicitly marked it `static`. [Issue #3497](https://github.com/projectlombok/lombok/issues/3497) [Issue #3559](https://github.com/projectlombok/lombok/issues/3559). +* BUGFIX: Eclipse projects using the `com.pro-crafting.tools:jasperreports-plugin` will now compile. +* BUGFIX: `@FieldNameConstants` now works when generated fields are involved. [Issue #3529](https://github.com/projectlombok/lombok/issues/3529). +* IMPROBABLE BREAKING CHANGE: For JSpecify, the package name changed from `org.jspecify.nullness` to `org.jspecify.annotations`, which might lead to a different null analysis. [Issue #3608](https://github.com/projectlombok/lombok/pull/3608). ### v1.18.30 (September 20th, 2023) * PLATFORM: Initial JDK21 support added. [Issue #3393](https://github.com/projectlombok/lombok/issues/3393). diff --git a/docker/gradle/Dockerfile b/docker/gradle/Dockerfile index cfb32939..b83f7f0e 100644 --- a/docker/gradle/Dockerfile +++ b/docker/gradle/Dockerfile @@ -7,7 +7,7 @@ RUN provision/jdk/java-${jdk}.sh ARG lombokjar=lombok.jar ADD https://projectlombok.org/downloads/${lombokjar} /lombok.jar -ARG gradle=8.3 +ARG gradle=8.5 ADD provision/gradle/gradle-${gradle}.sh provision/gradle/gradle-${gradle}.sh RUN provision/gradle/gradle-${gradle}.sh diff --git a/docker/gradle/readme.md b/docker/gradle/readme.md index 5b827801..2579f032 100644 --- a/docker/gradle/readme.md +++ b/docker/gradle/readme.md @@ -2,11 +2,12 @@ [_(general configuration and options)_](../readme.md) -### `ARG gradle=8.3` +### `ARG gradle=8.5` The gradle version to be used. Supported values: -- `8.3` (default) +- `8.5` (default) +- `8.3` - `7.6.1` - `6.8.3` diff --git a/docker/provision/gradle/gradle-8.5.sh b/docker/provision/gradle/gradle-8.5.sh new file mode 100755 index 00000000..2f13a210 --- /dev/null +++ b/docker/provision/gradle/gradle-8.5.sh @@ -0,0 +1,4 @@ +apt-get update && apt-get install -y wget unzip +wget https://github.com/gradle/gradle-distributions/releases/download/v8.5.0/gradle-8.5-bin.zip -O gradle.zip +mkdir /opt/gradle && unzip -d /opt/gradle gradle.zip +mv /opt/gradle/gradle-8.5 /opt/gradle/gradle diff --git a/docker/provision/jdk/java-22.sh b/docker/provision/jdk/java-22.sh old mode 100644 new mode 100755 index 08d8c00a..69135bfd --- a/docker/provision/jdk/java-22.sh +++ b/docker/provision/jdk/java-22.sh @@ -1,4 +1,4 @@ apt-get update && apt-get install -y wget -wget https://download.java.net/java/early_access/jdk22/15/GPL/openjdk-22-ea+15_linux-x64_bin.tar.gz -O jdk.tar.gz +wget https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_linux-x64_bin.tar.gz -O jdk.tar.gz tar -xzf jdk.tar.gz -C /opt/ -mv /opt/jdk-22 /opt/jdk \ No newline at end of file +mv /opt/jdk-22 /opt/jdk diff --git a/docker/readme.md b/docker/readme.md index deb482f5..7bd05c64 100644 --- a/docker/readme.md +++ b/docker/readme.md @@ -13,7 +13,7 @@ By default, this is the latest released version. You can download a specific ver ### `ARG jdk=21` The jdk version to be used. Supported values: -- `22`(experimental, based on openjdk early access) +- `22`(based on openjdk GA) - `21` (default)(based on openjdk instead of adoptium) - `17` - `11` diff --git a/src/core/lombok/bytecode/FixedClassWriter.java b/src/core/lombok/bytecode/FixedClassWriter.java index f18dc3a4..6d86fe9d 100644 --- a/src/core/lombok/bytecode/FixedClassWriter.java +++ b/src/core/lombok/bytecode/FixedClassWriter.java @@ -28,6 +28,10 @@ class FixedClassWriter extends ClassWriter { FixedClassWriter(ClassReader classReader, int flags) { super(classReader, flags); } + + FixedClassWriter(int flags) { + super(flags); + } @Override protected String getCommonSuperClass(String type1, String type2) { //By default, ASM will attempt to live-load the class types, which will fail if meddling with classes in an @@ -40,4 +44,4 @@ class FixedClassWriter extends ClassWriter { return "java/lang/Object"; } } -} \ No newline at end of file +} diff --git a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java index 8ae7af5b..654a308a 100644 --- a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java +++ b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java @@ -44,7 +44,7 @@ public class PreventNullAnalysisRemover implements PostCompilerTransformation { byte[] fixedByteCode = fixJSRInlining(original); ClassReader reader = new ClassReader(fixedByteCode); - ClassWriter writer = new FixedClassWriter(reader, 0); + ClassWriter writer = new FixedClassWriter(0); final AtomicBoolean changesMade = new AtomicBoolean(); diff --git a/src/core/lombok/bytecode/SneakyThrowsRemover.java b/src/core/lombok/bytecode/SneakyThrowsRemover.java index ea1c3cec..b716245d 100644 --- a/src/core/lombok/bytecode/SneakyThrowsRemover.java +++ b/src/core/lombok/bytecode/SneakyThrowsRemover.java @@ -46,7 +46,7 @@ public class SneakyThrowsRemover implements PostCompilerTransformation { byte[] fixedByteCode = fixJSRInlining(original); ClassReader reader = new ClassReader(fixedByteCode); - ClassWriter writer = new ClassWriter(reader, 0); + ClassWriter writer = new ClassWriter(0); final AtomicBoolean changesMade = new AtomicBoolean(); diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index c8471879..7caf52da 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2023 The Project Lombok Authors. + * Copyright (C) 2009-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,7 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.18.31"; + private static final String VERSION = "1.18.33"; private static final String RELEASE_NAME = "Edgy Guinea Pig"; // private static final String RELEASE_NAME = "Envious Ferret"; diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index e8b89aad..defa746c 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -115,6 +115,7 @@ public class HandlerUtil { "org.eclipse.jdt.annotation.NonNull", "org.jetbrains.annotations.NotNull", "org.jmlspecs.annotation.NonNull", + "org.jspecify.annotations.NonNull", "org.netbeans.api.annotations.common.NonNull", "org.springframework.lang.NonNull", "reactor.util.annotation.NonNull", @@ -185,8 +186,8 @@ public class HandlerUtil { "org.jetbrains.annotations.UnknownNullability", "org.jmlspecs.annotation.NonNull", "org.jmlspecs.annotation.Nullable", - "org.jspecify.nullness.Nullable", - "org.jspecify.nullness.NullnessUnspecified", + "org.jspecify.annotations.Nullable", + "org.jspecify.annotations.NonNull", "org.netbeans.api.annotations.common.CheckForNull", "org.netbeans.api.annotations.common.NonNull", "org.netbeans.api.annotations.common.NullAllowed", diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index 4950aeef..cd7bae76 100644 --- a/src/core/lombok/eclipse/EclipseNode.java +++ b/src/core/lombok/eclipse/EclipseNode.java @@ -217,7 +217,7 @@ public class EclipseNode extends lombok.core.LombokNode { TYPE_MAP = Collections.unmodifiableMap(m); } - private static char[] valueName = "value".toCharArray(); + private static char[] valueName = "$value".toCharArray(); private static char[] actualValueName = "actualValue".toCharArray(); private static final int PARENTHESIZED = (1 << ASTNode.ParenthesizedSHIFT) & ASTNode.ParenthesizedMASK; diff --git a/src/core/lombok/eclipse/handlers/HandleLocked.java b/src/core/lombok/eclipse/handlers/HandleLocked.java index 240a6498..ab733c97 100644 --- a/src/core/lombok/eclipse/handlers/HandleLocked.java +++ b/src/core/lombok/eclipse/handlers/HandleLocked.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 The Project Lombok Authors. + * Copyright (C) 2021-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,15 +21,19 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.EcjAugments.ASTNode_handled; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; + +import lombok.Locked; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.Locked; import lombok.spi.Provides; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; /** * Handles the {@code lombok.Locked} annotation for eclipse. @@ -52,5 +56,11 @@ public class HandleLocked extends EclipseAnnotationHandler { @Override public void preHandle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { String annotationValue = annotation.getInstance().value(); HandleLockedUtil.preHandle(annotationValue, LOCK_TYPE_CLASS, LOCK_IMPL_CLASS, annotationNode); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleLockedRead.java b/src/core/lombok/eclipse/handlers/HandleLockedRead.java index a293467a..33f2583b 100644 --- a/src/core/lombok/eclipse/handlers/HandleLockedRead.java +++ b/src/core/lombok/eclipse/handlers/HandleLockedRead.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 The Project Lombok Authors. + * Copyright (C) 2021-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,15 +21,19 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.EcjAugments.ASTNode_handled; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; + +import lombok.Locked; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.Locked; import lombok.spi.Provides; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; /** * Handles the {@code lombok.Locked.Read} annotation for eclipse. @@ -53,5 +57,11 @@ public class HandleLockedRead extends EclipseAnnotationHandler { @Override public void preHandle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { String annotationValue = annotation.getInstance().value(); HandleLockedUtil.preHandle(annotationValue, LOCK_TYPE_CLASS, LOCK_IMPL_CLASS, annotationNode); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleLockedWrite.java b/src/core/lombok/eclipse/handlers/HandleLockedWrite.java index 6192c76b..548b4d4a 100644 --- a/src/core/lombok/eclipse/handlers/HandleLockedWrite.java +++ b/src/core/lombok/eclipse/handlers/HandleLockedWrite.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 The Project Lombok Authors. + * Copyright (C) 2021-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,15 +21,19 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.EcjAugments.ASTNode_handled; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; + +import lombok.Locked; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.Locked; import lombok.spi.Provides; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; /** * Handles the {@code lombok.Locked.Write} annotation for eclipse. @@ -53,5 +57,11 @@ public class HandleLockedWrite extends EclipseAnnotationHandler { @Override public void preHandle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { String annotationValue = annotation.getInstance().value(); HandleLockedUtil.preHandle(annotationValue, LOCK_TYPE_CLASS, LOCK_IMPL_CLASS, annotationNode); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java index 5f0ca3fb..74d9df6f 100644 --- a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +22,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.eclipse.EcjAugments.ASTNode_handled; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; @@ -29,15 +30,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import lombok.ConfigurationKeys; -import lombok.SneakyThrows; -import lombok.core.AnnotationValues; -import lombok.core.HandlerPriority; -import lombok.eclipse.DeferUntilPostDiet; -import lombok.eclipse.EclipseAnnotationHandler; -import lombok.eclipse.EclipseNode; -import lombok.spi.Provides; - import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -58,6 +50,15 @@ import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import lombok.ConfigurationKeys; +import lombok.SneakyThrows; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.eclipse.DeferUntilPostDiet; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; + /** * Handles the {@code lombok.HandleSneakyThrows} annotation for eclipse. */ @@ -76,6 +77,15 @@ public class HandleSneakyThrows extends EclipseAnnotationHandler { } } + @Override + public void preHandle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, ast, annotationNode); + ASTNode_handled.set(ast, true); + } + } + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.SNEAKY_THROWS_FLAG_USAGE, "@SneakyThrows"); diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index dbe363d9..c5fbcf4f 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +22,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.eclipse.EcjAugments.ASTNode_handled; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; @@ -70,6 +71,12 @@ public class HandleSynchronized extends EclipseAnnotationHandler { if (method.isAbstract()) return; createLockField(annotation, annotationNode, new boolean[] {method.isStatic()}, false); + + if (hasParsedBody(getAnnotatedMethod(annotationNode))) { + // This method has a body in diet mode, so we have to handle it now. + handle(annotation, source, annotationNode); + ASTNode_handled.set(source, true); + } } public char[] createLockField(AnnotationValues annotation, EclipseNode annotationNode, boolean[] isStatic, boolean reportErrors) { diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index fca0d0d1..3e180d84 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -288,7 +288,7 @@ public class JavacNode extends lombok.core.LombokNode { } if (copyOfBoxedFieldType == null) copyOfBoxedFieldType = copyType(maker, field, source); - Name valueName = fieldNode.toName("value"); + Name valueName = fieldNode.toName("$value"); Name actualValueName = fieldNode.toName("actualValue"); /* java.lang.Object value = this.fieldName.get();*/ { diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 3a230437..d64daf38 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -1108,6 +1108,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { typeParamsForBuilderParameter.append(copySelect(maker, (JCFieldAccess) typeParam)); } else if (typeParam instanceof JCTypeApply) { typeParamsForBuilderParameter.append(cloneType(maker, (JCTypeApply)typeParam, source)); + } else if (JCAnnotatedTypeReflect.is(typeParam)) { + typeParamsForBuilderParameter.append(cloneType(maker, (JCExpression)typeParam, source)); } } return typeParamsForBuilderParameter; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index a252a726..8b563824 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -2033,13 +2033,13 @@ public class JavacHandlerUtil { public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode type, List params) { JCClassDecl td = (JCClassDecl) type.get(); - boolean instance = (td.mods.flags & Flags.STATIC) == 0; + boolean instance = !type.isStatic(); return namePlusTypeParamsToTypeReference(maker, type.up(), td.name, instance, params, List.nil()); } public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode type, List params, List annotations) { JCClassDecl td = (JCClassDecl) type.get(); - boolean instance = (td.mods.flags & Flags.STATIC) == 0; + boolean instance = !type.isStatic(); return namePlusTypeParamsToTypeReference(maker, type.up(), td.name, instance, params, annotations); } @@ -2051,7 +2051,7 @@ public class JavacHandlerUtil { JCExpression r = null; if (parentType != null && parentType.getKind() == Kind.TYPE && !parentType.getName().isEmpty()) { JCClassDecl td = (JCClassDecl) parentType.get(); - boolean outerInstance = instance && ((td.mods.flags & Flags.STATIC) == 0); + boolean outerInstance = instance && !parentType.isStatic(); List outerParams = instance ? td.typarams : List.nil(); r = namePlusTypeParamsToTypeReference(maker, parentType.up(), td.name, outerInstance, outerParams, List.nil()); } diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index d7434454..85598d32 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2021 The Project Lombok Authors. + * Copyright (C) 2016-2024 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 @@ -263,6 +263,14 @@ public class PrettyPrinter extends JCTree.Visitor { return false; } + private void print(Name name) { + if (name.isEmpty()) { + print("_"); + } else { + print(name.toString()); + } + } + private void print(CharSequence s) { boolean align = needsAlign; if (needsNewLine && !onNewLine) println(); @@ -1722,6 +1730,8 @@ public class PrettyPrinter extends JCTree.Visitor { printPatternCaseLabel(tree); } else if (className.endsWith("$JCRecordPattern")) { // Introduced in JDK19 printRecordPattern(tree); + } else if (className.endsWith("$JCAnyPattern")) { // Introduced in JDK22 + print("_"); } else { throw new AssertionError("Unhandled tree type: " + tree.getClass() + ": " + tree); } diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 9b6350e3..e3a52ba1 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2023 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -100,6 +100,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchJavadoc(sm); patchASTConverterLiterals(sm); patchASTNodeSearchUtil(sm); + patchFieldInitializer(sm); patchPostCompileHookEcj(sm); @@ -770,6 +771,13 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .request(StackRequest.RETURN_VALUE, StackRequest.THIS) .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Delegate", "addGeneratedDelegateMethods", "java.lang.Object[]", "java.lang.Object", "java.lang.Object")) .build()); + + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.core.JavaElement", "getElementInfo", "org.eclipse.jdt.internal.compiler.env.IElementInfo")) + .request(StackRequest.THIS) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$Delegate", "isDelegateSourceMethod", "boolean", "java.lang.Object")) + .valueMethod(new Hook("lombok.launch.PatchFixesHider$Delegate", "returnElementInfo", "java.lang.Object", "java.lang.Object")) + .build()); } private static void addPatchesForValEclipse(ScriptManager sm) { @@ -966,6 +974,14 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { } private static void patchJavadoc(ScriptManager sm) { + // Moved to new package and changed to instance method in 2024-03 + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavadocAccess", "getHTMLContent", "java.lang.String", "org.eclipse.jdt.core.IJavaElement", "boolean")) + .methodToWrap(new Hook("org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavadocAccess", "getHTMLContentFromSource", "java.lang.String", "org.eclipse.jdt.core.IJavaElement")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Javadoc", "getHTMLContentFromSource", "java.lang.String", "java.lang.String", "java.lang.Object", "org.eclipse.jdt.core.IJavaElement")) + .requestExtra(StackRequest.THIS, StackRequest.PARAM1) + .build()); + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2", "getHTMLContent", "java.lang.String", "org.eclipse.jdt.core.IJavaElement", "boolean")) .methodToWrap(new Hook("org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2", "getHTMLContentFromSource", "java.lang.String", "org.eclipse.jdt.core.IJavaElement")) @@ -989,13 +1005,6 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .requestExtra(StackRequest.PARAM1) .build()); - sm.addScript(ScriptBuilder.replaceMethodCall() - .target(new MethodTarget("org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "printBody", "java.lang.StringBuffer", "int", "java.lang.StringBuffer")) - .methodToReplace(new Hook("org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "print", "java.lang.StringBuffer", "int", "java.lang.StringBuffer")) - .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Javadoc", "printMethod", "java.lang.StringBuffer", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "int", "java.lang.StringBuffer", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration")) - .requestExtra(StackRequest.THIS) - .build()); - sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.addField() .fieldName("$javadoc") .fieldType("Ljava/util/Map;") @@ -1036,6 +1045,42 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .build()); } + private static void patchFieldInitializer(ScriptManager sm) { + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.addField() + .targetClass("org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor") + .fieldName("$fieldInfo") + .fieldType("Ljava/lang/Object;") + .build()); + + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.addField() + .targetClass("org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor") + .fieldName("$sourceFieldElementInfo") + .fieldType("Lorg/eclipse/jdt/internal/core/SourceFieldElementInfo;") + .build()); + + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor", "exitField", "void", "int", "int", "int")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$FieldInitializer", "storeFieldInfo", "boolean", "org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor")) + .request(StackRequest.THIS) + .transplant() + .build()); + + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor", "exitField", "void", "int", "int", "int")) + .methodToWrap(new Hook("org.eclipse.jdt.internal.core.SourceFieldElementInfo", "", "void")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$FieldInitializer", "storeSourceFieldElementInfo", "void", "org.eclipse.jdt.internal.core.SourceFieldElementInfo", "org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor")) + .requestExtra(StackRequest.THIS) + .transplant() + .build()); + + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapReturnValue() + .target(new MethodTarget("org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor", "exitField", "void", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$FieldInitializer", "overwriteInitializer", "void", "org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor")) + .request(StackRequest.THIS) + .transplant() + .build()); + } + private static void patchCrossModuleClassLoading(ScriptManager sm) { sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.jdt.internal.compiler.parser.Parser", "")) @@ -1044,14 +1089,40 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { } private static void patchForTests(ScriptManager sm) { - sm.addScriptIfWitness(new String[] {"lombok/eclipse/EclipseRunner"}, ScriptBuilder.wrapReturnValue() + String[] ECLIPSE_TEST_CLASSES = new String[] {"lombok/transform/TestWithEcj", "lombok/eclipse/EclipseRunner"}; + + // Add support for javadoc in tests + sm.addScriptIfWitness(ECLIPSE_TEST_CLASSES, ScriptBuilder.replaceMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "printBody", "java.lang.StringBuilder", "int", "java.lang.StringBuilder")) + .methodToReplace(new Hook("org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "print", "java.lang.StringBuilder", "int", "java.lang.StringBuilder")) + .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Tests", "printMethod", "java.lang.StringBuilder", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "int", "java.lang.StringBuilder", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration")) + .requestExtra(StackRequest.THIS) + .build()); + + sm.addScriptIfWitness(ECLIPSE_TEST_CLASSES, ScriptBuilder.replaceMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "printBody", "java.lang.StringBuffer", "int", "java.lang.StringBuffer")) + .methodToReplace(new Hook("org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "print", "java.lang.StringBuffer", "int", "java.lang.StringBuffer")) + .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Tests", "printMethod", "java.lang.StringBuffer", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "int", "java.lang.StringBuffer", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration")) + .requestExtra(StackRequest.THIS) + .build()); + + sm.addScriptIfWitness(ECLIPSE_TEST_CLASSES, ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.osgi.framework.FrameworkUtil", "getBundle", "org.osgi.framework.Bundle", "java.lang.Class")) .request(StackRequest.RETURN_VALUE, StackRequest.PARAM1) .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Tests", "getBundle", "java.lang.Object", "java.lang.Object", "java.lang.Class")) .build()); - sm.addScriptIfWitness(new String[] {"lombok/transform/TestWithEcj"}, ScriptBuilder.exitEarly() - .target(new MethodTarget("org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "print")) + // Remove implicit canonical constructors in tests + sm.addScriptIfWitness(ECLIPSE_TEST_CLASSES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "print", "java.lang.StringBuilder", "int", "java.lang.StringBuilder")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$Tests", "isImplicitCanonicalConstructor", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "java.lang.Object")) + .valueMethod(new Hook("lombok.launch.PatchFixesHider$Tests", "returnStringBuilder", "java.lang.StringBuilder", "java.lang.Object", "java.lang.StringBuilder")) + .request(StackRequest.THIS, StackRequest.PARAM2) + .transplant() + .build()); + + sm.addScriptIfWitness(ECLIPSE_TEST_CLASSES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "print", "java.lang.StringBuffer", "int", "java.lang.StringBuffer")) .decisionMethod(new Hook("lombok.launch.PatchFixesHider$Tests", "isImplicitCanonicalConstructor", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "java.lang.Object")) .valueMethod(new Hook("lombok.launch.PatchFixesHider$Tests", "returnStringBuffer", "java.lang.StringBuffer", "java.lang.Object", "java.lang.StringBuffer")) .request(StackRequest.THIS, StackRequest.PARAM2) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java index d7b17598..fee6db43 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2021 The Project Lombok Authors. + * Copyright (C) 2010-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,10 +21,11 @@ */ package lombok.eclipse.agent; -import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.EcjAugments.*; +import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; @@ -726,6 +727,15 @@ public class PatchDelegate { return EclipseOnlyMethods.addGeneratedDelegateMethodsToChildren(returnValue, javaElement); } + public static Object returnElementInfo(Object delegateSourceMethod) { + Field field = Permit.permissiveGetField(delegateSourceMethod.getClass(), "sourceMethodInfo"); + return Permit.permissiveReadField(Object.class, field, delegateSourceMethod); + } + + public static boolean isDelegateSourceMethod(Object sourceMethod) { + return sourceMethod.getClass().getName().equals("lombok.eclipse.agent.PatchDelegate$EclipseOnlyMethods$DelegateSourceMethod"); + } + public static class EclipseOnlyMethods { private static void cleanupDelegateMethods(CompilationUnitDeclaration cud) { CompilationUnit compilationUnit = getCompilationUnit(cud); diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java index 3b89c0af..555c84b0 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2023 The Project Lombok Authors. + * Copyright (C) 2012-2024 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 @@ -321,9 +321,11 @@ public class PatchExtensionMethod { MethodBinding fixedBinding = scope.getMethod(extensionMethod.declaringClass, methodCall.selector, argumentTypes.toArray(new TypeBinding[0]), methodCall); if (fixedBinding instanceof ProblemMethodBinding) { methodCall.arguments = originalArgs; - if (fixedBinding.declaringClass != null) { - PostponedInvalidMethodError.invoke(scope.problemReporter(), methodCall, fixedBinding, scope); + // Sometimes the declaring class is null, in that case we have to create a new ProblemMethodBinding using the extension method's declaring class + if (fixedBinding.declaringClass == null) { + fixedBinding = new ProblemMethodBinding(fixedBinding.selector, fixedBinding.parameters, extensionMethod.declaringClass, fixedBinding.problemId()); } + PostponedInvalidMethodError.invoke(scope.problemReporter(), methodCall, fixedBinding, scope); } else { // If the extension method uses varargs, the last fixed binding parameter is an array but // the method arguments are not. Even thought we already know that the method is fine we still diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java index 673c30fd..caa94e2f 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 The Project Lombok Authors. + * Copyright (C) 2020-2024 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 @@ -29,19 +29,15 @@ import java.util.Map; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.internal.compiler.ast.ASTNode; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.core.CompilationUnit; import org.eclipse.jdt.internal.core.SourceMethod; import org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2; -import lombok.eclipse.handlers.EclipseHandlerUtil; import lombok.permit.Permit; public class PatchJavadoc { - public static String getHTMLContentFromSource(String original, Object member) { + public static String getHTMLContentFromSource(Object instance, String original, Object member) { if (original != null) { return original; } @@ -58,27 +54,13 @@ public class PatchJavadoc { String rawJavadoc = docs.get(signature); if (rawJavadoc == null) return null; - return Reflection.javadoc2HTML((IMember) member, (IJavaElement) member, rawJavadoc); + return Reflection.javadoc2HTML(instance, (IMember) member, (IJavaElement) member, rawJavadoc); } } return null; } - - public static StringBuffer printMethod(AbstractMethodDeclaration methodDeclaration, Integer tab, StringBuffer output, TypeDeclaration type) { - Map docs = CompilationUnit_javadoc.get(methodDeclaration.compilationResult.compilationUnit); - if (docs != null) { - String signature = EclipseHandlerUtil.getSignature(type, methodDeclaration); - String rawJavadoc = docs.get(signature); - if (rawJavadoc != null) { - for (String line : rawJavadoc.split("\r?\n")) { - ASTNode.printIndent(tab, output).append(line).append("\n"); - } - } - } - return methodDeclaration.print(tab, output); - } - + private static class Signature { static final String getSignature(SourceMethod sourceMethod) { StringBuilder sb = new StringBuilder(); @@ -103,9 +85,10 @@ public class PatchJavadoc { private static class Reflection { private static final Method javadoc2HTML; private static final Method oldJavadoc2HTML; + private static final Method reallyOldJavadoc2HTML; private static final Method lsJavadoc2HTML; static { - Method a = null, b = null, c = null; + Method a = null, b = null, c = null, d = null; try { a = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, IJavaElement.class, String.class); @@ -116,30 +99,41 @@ public class PatchJavadoc { try { c = Permit.getMethod(Class.forName("org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2"), "javadoc2HTML", IMember.class, IJavaElement.class, String.class); } catch (Throwable t) {} + try { + d = Permit.getMethod(Class.forName("org.eclipse.jdt.core.manipulation.internal.javadoc.CoreJavadocAccess"), "javadoc2HTML", IMember.class, IJavaElement.class, String.class); + } catch (Throwable t) {} - javadoc2HTML = a; - oldJavadoc2HTML = b; + oldJavadoc2HTML = a; + reallyOldJavadoc2HTML = b; lsJavadoc2HTML = c; + javadoc2HTML = d; } - private static String javadoc2HTML(IMember member, IJavaElement element, String rawJavadoc) { + private static String javadoc2HTML(Object instance, IMember member, IJavaElement element, String rawJavadoc) { if (javadoc2HTML != null) { try { - return (String) javadoc2HTML.invoke(null, member, element, rawJavadoc); - } catch (Throwable t) { - return null; - } - } - if (lsJavadoc2HTML != null) { - try { - return (String) lsJavadoc2HTML.invoke(null, member, element, rawJavadoc); + return (String) javadoc2HTML.invoke(instance, member, element, rawJavadoc); } catch (Throwable t) { return null; } } if (oldJavadoc2HTML != null) { try { - return (String) oldJavadoc2HTML.invoke(null, member, rawJavadoc); + return (String) oldJavadoc2HTML.invoke(instance, member, element, rawJavadoc); + } catch (Throwable t) { + return null; + } + } + if (lsJavadoc2HTML != null) { + try { + return (String) lsJavadoc2HTML.invoke(instance, member, element, rawJavadoc); + } catch (Throwable t) { + return null; + } + } + if (reallyOldJavadoc2HTML != null) { + try { + return (String) reallyOldJavadoc2HTML.invoke(instance, member, rawJavadoc); } catch (Throwable t) { return null; } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index 62c38e5e..7ba663cc 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023 The Project Lombok Authors. + * Copyright (C) 2010-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,7 @@ */ package lombok.launch; -import static lombok.eclipse.EcjAugments.ASTNode_generatedBy; +import static lombok.eclipse.EcjAugments.*; import static lombok.eclipse.Eclipse.*; import java.io.BufferedOutputStream; @@ -33,6 +33,7 @@ import java.lang.reflect.Method; import java.security.CodeSource; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Stack; import org.eclipse.core.runtime.CoreException; @@ -51,7 +52,9 @@ import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.internal.compiler.ISourceElementRequestor.FieldInfo; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; @@ -60,7 +63,9 @@ import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.parser.Parser; +import org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor; import org.eclipse.jdt.internal.core.SourceField; +import org.eclipse.jdt.internal.core.SourceFieldElementInfo; import org.eclipse.jdt.internal.core.dom.rewrite.NodeRewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; @@ -69,6 +74,7 @@ import org.eclipse.jdt.internal.corext.refactoring.code.CallContext; import org.eclipse.jdt.internal.corext.refactoring.code.SourceProvider; import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment; +import lombok.eclipse.handlers.EclipseHandlerUtil; import lombok.permit.Permit; /** These contain a mix of the following: @@ -271,11 +277,16 @@ final class PatchFixesHider { public static final class Delegate { private static final Method HANDLE_DELEGATE_FOR_TYPE; private static final Method ADD_GENERATED_DELEGATE_METHODS; + public static final Method IS_DELEGATE_SOURCE_METHOD; + public static final Method RETURN_ELEMENT_INFO; static { - Class shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchDelegatePortal"); - HANDLE_DELEGATE_FOR_TYPE = Util.findMethod(shadowed, "handleDelegateForType", Object.class); - ADD_GENERATED_DELEGATE_METHODS = Util.findMethod(shadowed, "addGeneratedDelegateMethods", Object.class, Object.class); + Class shadowedPortal = Util.shadowLoadClass("lombok.eclipse.agent.PatchDelegatePortal"); + HANDLE_DELEGATE_FOR_TYPE = Util.findMethod(shadowedPortal, "handleDelegateForType", Object.class); + ADD_GENERATED_DELEGATE_METHODS = Util.findMethod(shadowedPortal, "addGeneratedDelegateMethods", Object.class, Object.class); + Class shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchDelegate"); + IS_DELEGATE_SOURCE_METHOD = Util.findMethod(shadowed, "isDelegateSourceMethod", Object.class); + RETURN_ELEMENT_INFO = Util.findMethod(shadowed, "returnElementInfo", Object.class); } public static boolean handleDelegateForType(Object classScope) { @@ -285,6 +296,14 @@ final class PatchFixesHider { public static Object[] addGeneratedDelegateMethods(Object returnValue, Object javaElement) { return (Object[]) Util.invokeMethod(ADD_GENERATED_DELEGATE_METHODS, returnValue, javaElement); } + + public static boolean isDelegateSourceMethod(Object sourceMethod) { + return (Boolean) Util.invokeMethod(IS_DELEGATE_SOURCE_METHOD, sourceMethod); + } + + public static Object returnElementInfo(Object delegateSourceMethod) { + return Util.invokeMethod(RETURN_ELEMENT_INFO, delegateSourceMethod); + } } /** Contains patch code to support {@code val} (eclipse specific) */ @@ -426,20 +445,18 @@ final class PatchFixesHider { /** Contains patch code to support Javadoc for generated methods */ public static final class Javadoc { private static final Method GET_HTML; - private static final Method PRINT_METHOD; static { Class shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchJavadoc"); - GET_HTML = Util.findMethod(shadowed, "getHTMLContentFromSource", String.class, Object.class); - PRINT_METHOD = Util.findMethod(shadowed, "printMethod", AbstractMethodDeclaration.class, Integer.class, StringBuffer.class, TypeDeclaration.class); + GET_HTML = Util.findMethod(shadowed, "getHTMLContentFromSource", Object.class, String.class, Object.class); } public static String getHTMLContentFromSource(String original, IJavaElement member) { - return (String) Util.invokeMethod(GET_HTML, original, member); + return (String) Util.invokeMethod(GET_HTML, null, original, member); } - public static StringBuffer printMethod(AbstractMethodDeclaration methodDeclaration, int tab, StringBuffer output, TypeDeclaration type) { - return (StringBuffer) Util.invokeMethod(PRINT_METHOD, methodDeclaration, tab, output, type); + public static String getHTMLContentFromSource(String original, Object instance, IJavaElement member) { + return (String) Util.invokeMethod(GET_HTML, instance, original, member); } } @@ -928,7 +945,99 @@ final class PatchFixesHider { } } + public static class FieldInitializer { + public static final Field INFO_STACK; + public static final Field FIELD_INFO; + public static final Field SOURCE_FIELD_ELEMENT_INFO; + public static final Field INITIALIZATION_SOURCE; + public static final Field NODE; + public static final boolean INITIALIZED; + + static { + INFO_STACK = Permit.permissiveGetField(CompilationUnitStructureRequestor.class, "infoStack"); + FIELD_INFO = Permit.permissiveGetField(CompilationUnitStructureRequestor.class, "$fieldInfo"); + SOURCE_FIELD_ELEMENT_INFO = Permit.permissiveGetField(CompilationUnitStructureRequestor.class, "$sourceFieldElementInfo"); + INITIALIZATION_SOURCE = Permit.permissiveGetField(SourceFieldElementInfo.class, "initializationSource"); + NODE = Permit.permissiveGetField(FieldInfo.class, "node"); + INITIALIZED = INFO_STACK != null && FIELD_INFO != null && SOURCE_FIELD_ELEMENT_INFO != null && INITIALIZATION_SOURCE != null && NODE != null; + } + + public static boolean storeFieldInfo(CompilationUnitStructureRequestor compilationUnitStructureRequestor) { + try { + if (INITIALIZED) { + Stack infoStack = Permit.get(INFO_STACK, compilationUnitStructureRequestor); + Object fieldInfo = infoStack.peek(); + Permit.set(FIELD_INFO, compilationUnitStructureRequestor, fieldInfo); + } + } catch (Exception e) { + // do not break eclipse + } + return false; + } + public static void storeSourceFieldElementInfo(SourceFieldElementInfo fieldInfo, CompilationUnitStructureRequestor compilationUnitStructureRequestor) { + try { + if (INITIALIZED) { + Permit.set(SOURCE_FIELD_ELEMENT_INFO, compilationUnitStructureRequestor, fieldInfo); + } + } catch (Exception e) { + // do not break eclipse + } + } + + public static void overwriteInitializer(CompilationUnitStructureRequestor compilationUnitStructureRequestor) { + try { + if (INITIALIZED) { + FieldInfo fieldInfo = Permit.get(FIELD_INFO, compilationUnitStructureRequestor); + Permit.set(FIELD_INFO, compilationUnitStructureRequestor, null); + + SourceFieldElementInfo sourceFieldElementInfo = Permit.get(SOURCE_FIELD_ELEMENT_INFO,compilationUnitStructureRequestor); + Permit.set(SOURCE_FIELD_ELEMENT_INFO, compilationUnitStructureRequestor, null); + + if (sourceFieldElementInfo.getInitializationSource() != null) { + AbstractVariableDeclaration node = Permit.get(NODE, fieldInfo); + + if (PatchFixes.isGenerated(node)) { + Permit.set(INITIALIZATION_SOURCE, sourceFieldElementInfo, node.initialization.toString().toCharArray()); + } + } + } + } catch (Exception e) { + // do not break eclipse + } + } + } + public static class Tests { + public static StringBuffer printMethod(AbstractMethodDeclaration methodDeclaration, int tab, StringBuffer output, TypeDeclaration type) { + return (StringBuffer) printMethod(methodDeclaration, tab, (Object) output, type); + } + + public static StringBuilder printMethod(AbstractMethodDeclaration methodDeclaration, int tab, StringBuilder output, TypeDeclaration type) { + return (StringBuilder) printMethod(methodDeclaration, tab, (Object) output, type); + } + + public static Object printMethod(AbstractMethodDeclaration methodDeclaration, int tab, Object output, TypeDeclaration type) { + Map docs = CompilationUnit_javadoc.get(methodDeclaration.compilationResult.compilationUnit); + Method printIndent = Permit.permissiveGetMethod(org.eclipse.jdt.internal.compiler.ast.ASTNode.class, "printIndent", int.class, output.getClass()); + if (docs != null) { + String signature = EclipseHandlerUtil.getSignature(type, methodDeclaration); + String rawJavadoc = docs.get(signature); + if (rawJavadoc != null) { + for (String line : rawJavadoc.split("\r?\n")) { + try { + Appendable sb = (Appendable) Permit.invoke(printIndent, null, tab, output); + sb.append(line).append("\n"); + } catch (Throwable e) { + // Ignore + } + } + } + } + Method printMethodDeclaration = Permit.permissiveGetMethod(AbstractMethodDeclaration.class, "print", int.class, output.getClass()); + Permit.invokeSneaky(printMethodDeclaration, methodDeclaration, tab, output); + return output; + } + public static Object getBundle(Object original, Class c) { if (original != null) { return original; @@ -958,5 +1067,9 @@ final class PatchFixesHider { public static StringBuffer returnStringBuffer(Object p1, StringBuffer buffer) { return buffer; } + + public static StringBuilder returnStringBuilder(Object p1, StringBuilder buffer) { + return buffer; + } } } diff --git a/src/support/lombok/eclipse/dependencies/DownloadEclipseDependencies.java b/src/support/lombok/eclipse/dependencies/DownloadEclipseDependencies.java index 2ff6839e..0e8d5895 100644 --- a/src/support/lombok/eclipse/dependencies/DownloadEclipseDependencies.java +++ b/src/support/lombok/eclipse/dependencies/DownloadEclipseDependencies.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022-2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse.dependencies; import java.io.BufferedInputStream; @@ -7,71 +28,57 @@ import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.List; +import java.util.Set; /** * Download eclipse bundles. */ public class DownloadEclipseDependencies { - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws Exception { String target = args[0]; String eclipseVersion = args[1]; - String updatePage = args[2]; - String[] packages = Arrays.copyOfRange(args, 3, args.length); + String updateSiteUrl = args[2]; + boolean resolveDependencies = Boolean.parseBoolean(args[3]); + List bundles = Arrays.asList(Arrays.copyOfRange(args, 4, args.length)); + + UpdateSite updateSite = new UpdateSite(); + updateSite.read(updateSiteUrl); + + final Set artifacts; + if (resolveDependencies) { + artifacts = updateSite.resolveWithDependencies(bundles); + } else { + artifacts = updateSite.resolveWithoutDependencies(bundles); + } String pluginTarget = target + "/" + eclipseVersion + "/plugins/"; + String pluginSource = updateSite.getResolvedUrl() + "/plugins/"; - String indexData = readUrlAsString(updatePage); - - for (String pkg : packages) { - Matcher matcher = Pattern.compile("(" + pkg.replace(".", "\\.") + "_.*?\\.jar)").matcher(indexData); - if (matcher.find()) { - String path = matcher.group(1); - - try { - downloadFile(path, updatePage, pluginTarget); - } catch (Exception e) { - } - - int index = path.lastIndexOf("_"); - String source = path.substring(0, index) + ".source" + path.substring(index); - if (indexData.contains(source)) { - try { - downloadFile(source, updatePage, pluginTarget); - } catch (Exception e) { - } - } - } else { - System.out.println("Bundle \"" + pkg + "\" not found"); + for (String artifact : artifacts) { + try { + downloadFile(artifact, pluginSource, pluginTarget); + } catch (Exception e) { + } + + int index = artifact.lastIndexOf("_"); + String source = artifact.substring(0, index) + ".source" + artifact.substring(index); + try { + downloadFile(source, pluginSource, pluginTarget); + } catch (Exception e) { } } writeEclipseLibrary(target, eclipseVersion); } - private static String readUrlAsString(String url) throws MalformedURLException, IOException { - InputStream in = getStreamForUrl(url); - - StringBuilder sb = new StringBuilder(); - - int bufferSize = 1024; - char[] buffer = new char[bufferSize]; - InputStreamReader reader = new InputStreamReader(in, "UTF-8"); - for (int count = 0; (count = reader.read(buffer, 0, bufferSize)) > 0;) { - sb.append(buffer, 0, count); - } - return sb.toString(); - } - private static void downloadFile(String filename, String repositoryUrl, String target) throws IOException { new File(target).mkdirs(); File targetFile = new File(target, filename); @@ -87,10 +94,13 @@ public class DownloadEclipseDependencies { out = new FileOutputStream(targetFile); copy(in, out); System.out.println("[done]"); - } catch(IOException e) { + } catch (IOException e) { System.out.println("[error]"); } finally { - if (in != null) try { in.close(); } catch (Exception ignore) {} + if (in != null) try { + in.close(); + } catch (Exception ignore) { + } if (out != null) out.close(); } } @@ -111,7 +121,7 @@ public class DownloadEclipseDependencies { InputStream in = new BufferedInputStream(connection.getInputStream()); return in; } - + private static void writeEclipseLibrary(String target, String eclipseVersion) throws IOException { StringBuilder sb = new StringBuilder(); sb.append("\n"); @@ -121,7 +131,8 @@ public class DownloadEclipseDependencies { sb.append("\" systemlibrary=\"false\">\n"); File[] files = new File(new File(target, eclipseVersion), "plugins").listFiles(new FilenameFilter() { - @Override public boolean accept(File dir, String name) { + @Override + public boolean accept(File dir, String name) { return name.endsWith(".jar") && !name.contains(".source_"); } }); diff --git a/src/support/lombok/eclipse/dependencies/UpdateSite.java b/src/support/lombok/eclipse/dependencies/UpdateSite.java new file mode 100644 index 00000000..40524568 --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/UpdateSite.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies; + +import java.io.BufferedInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXSource; + +import org.xml.sax.InputSource; + +import lombok.eclipse.dependencies.model.Child; +import lombok.eclipse.dependencies.model.Repository; +import lombok.eclipse.dependencies.model.Required; +import lombok.eclipse.dependencies.model.Unit; +import lombok.eclipse.dependencies.model.VersionRange; + +public class UpdateSite { + private static final String OS_NAME = System.getProperty("os.name").toLowerCase(); + private static final String OSGI_OS = OS_NAME.contains("windows") ? "windows" : OS_NAME.contains("mac") ? "mac" : "linux"; + private static final String OS_ARCH = System.getProperty("os.arch"); + private static final String OSGI_ARCH = OS_ARCH.equals("aarch64") ? "aarch64" : "x86_64"; + + private JAXBContext jaxbContext; + private Repository repository; + private String resolvedUrl; + private SAXParserFactory saxParserFactory; + + public UpdateSite() throws Exception { + jaxbContext = JAXBContext.newInstance(Repository.class); + + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + spf.setXIncludeAware(false); + saxParserFactory = spf; + } + + public void read(String url) throws Exception { + String currentUrl = url; + try { + while (true) { + String child = resolveNextChild(currentUrl); + if (child.startsWith("https://")) { + currentUrl = child; + } else { + currentUrl += child; + } + } + } catch (FileNotFoundException e) { + // Found the real repository + } + + resolvedUrl = currentUrl; + + try (InputStream inputStream = readJarOrXml(resolvedUrl, "content")) { + repository = unmarshalRepository(inputStream); + } + } + + public Set resolveWithoutDependencies(List dependencies) { + return resolve(dependencies, false); + } + + public Set resolveWithDependencies(List dependencies) { + return resolve(dependencies, true); + } + + private Set resolve(List dependencies, boolean withDependencies) { + Queue toResolve = new ArrayDeque<>(); + for (String dependency : dependencies) { + String[] split = dependency.split(":"); + Required required = new Required(); + required.namespace = split[0]; + required.name = split[1]; + required.range = VersionRange.ALL; + toResolve.add(required); + } + Set resolved = new HashSet<>(); + while (!toResolve.isEmpty()) { + Required next = toResolve.poll(); + + // Skip already resolved + if (resolved.stream().anyMatch(u -> u.satisfies(next))) { + continue; + } + + List satisfyingUnits = repository.units.stream().filter(u -> u.satisfies(next)).collect(Collectors.toList()); + // Skip unknown + if (satisfyingUnits.isEmpty()) { + System.out.println("Skipping unknown unit " + next); + continue; + } + + // Skip JDK dependencies + boolean jdkDependency = satisfyingUnits.stream().anyMatch(u -> u.id.equals("a.jre.javase")); + if (jdkDependency) { + continue; + } + + if (satisfyingUnits.size() > 1) { + System.out.println("Ambiguous resolution for " + next + ": " + satisfyingUnits.toString() + ", picking first"); + } + + Unit unit = satisfyingUnits.get(0); + resolved.add(unit); + + if (withDependencies && unit.requires != null) { + for (Required required : unit.requires) { + if (required.optional) continue; + if (!matchesFilter(required.filter)) continue; + + toResolve.add(required); + } + } + } + + return resolved.stream().map(u -> u.toString() + ".jar").collect(Collectors.toSet()); + } + + // Dummy implementation + private boolean matchesFilter(String filter) { + if (filter == null) { + return true; + } + if (filter.contains("osgi.arch=") && !filter.contains("osgi.arch=" + OSGI_ARCH)) { + return false; + } + if (filter.contains("osgi.os=") && !filter.contains("osgi.os=" + OSGI_OS)) { + return false; + } + return true; + } + + private String resolveNextChild(String currentUrl) throws Exception { + try (InputStream inputStream = readJarOrXml(currentUrl, "compositeContent")) { + Repository repository = unmarshalRepository(inputStream); + Child lastChild = repository.children.get(repository.children.size() - 1); + return lastChild.location; + } + } + + private Repository unmarshalRepository(InputStream inputStream) throws Exception { + Source source = new SAXSource(saxParserFactory.newSAXParser().getXMLReader(), new InputSource(inputStream)); + Repository repository = (Repository) jaxbContext.createUnmarshaller().unmarshal(source); + return repository; + } + + private InputStream readJarOrXml(String url, String name) throws Exception { + try { + return getStreamForUrl(url + "/" + name + ".xml"); + } catch (FileNotFoundException e) { + System.out.println("Not found, trying jar"); + } + ZipInputStream zipInputStream = new ZipInputStream(getStreamForUrl(url + "/" + name + ".jar")); + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + if (entry.getName().equals(name + ".xml")) { + return zipInputStream; + } + } + throw new FileNotFoundException(); + } + + private static InputStream getStreamForUrl(String url) throws Exception { + System.out.println("Reading " + url); + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); + connection.setRequestProperty("User-Agent", "lombok"); + connection.setRequestProperty("Accept", "*/*"); + InputStream in = new BufferedInputStream(connection.getInputStream()); + return in; + } + + public String getResolvedUrl() { + return resolvedUrl; + } +} diff --git a/src/support/lombok/eclipse/dependencies/model/Child.java b/src/support/lombok/eclipse/dependencies/model/Child.java new file mode 100644 index 00000000..1aedc77f --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/Child.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023-2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +import javax.xml.bind.annotation.XmlAttribute; + +public class Child { + @XmlAttribute + public String location; +} \ No newline at end of file diff --git a/src/support/lombok/eclipse/dependencies/model/Provided.java b/src/support/lombok/eclipse/dependencies/model/Provided.java new file mode 100644 index 00000000..29762f8c --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/Provided.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023-2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +public class Provided { + @XmlAttribute + public String namespace; + @XmlAttribute + public String name; + @XmlAttribute + @XmlJavaTypeAdapter(VersionAdapter.class) + public Version version; + + @Override + public String toString() { + return namespace + ":" + name + "_" + version; + } +} diff --git a/src/support/lombok/eclipse/dependencies/model/Repository.java b/src/support/lombok/eclipse/dependencies/model/Repository.java new file mode 100644 index 00000000..17c1b236 --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/Repository.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023-2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Repository { + @XmlElementWrapper(name = "children") + @XmlElement(name="child") + public List children; + + @XmlElementWrapper(name = "units") + @XmlElement(name="unit") + public List units; +} \ No newline at end of file diff --git a/src/support/lombok/eclipse/dependencies/model/Required.java b/src/support/lombok/eclipse/dependencies/model/Required.java new file mode 100644 index 00000000..0d5ae2d0 --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/Required.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023-2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +public class Required { + @XmlAttribute + public String namespace; + @XmlAttribute + public String name; + @XmlAttribute + @XmlJavaTypeAdapter(VersionRangeAdapter.class) + public VersionRange range; + @XmlAttribute + public boolean optional; + @XmlElement + public String filter; + + @Override + public String toString() { + return namespace + ":" + name + "_" + range; + } +} diff --git a/src/support/lombok/eclipse/dependencies/model/Unit.java b/src/support/lombok/eclipse/dependencies/model/Unit.java new file mode 100644 index 00000000..781651ec --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/Unit.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023-2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +import java.util.List; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +public class Unit { + @XmlAttribute + public String id; + @XmlAttribute + @XmlJavaTypeAdapter(VersionAdapter.class) + public Version version; + + @XmlElementWrapper(name = "provides") + @XmlElement(name="provided") + public List provides; + + @XmlElementWrapper(name = "requires") + @XmlElement(name="required") + public List requires; + + public boolean satisfies(Required required) { + return provides.stream().anyMatch(p -> p.namespace.equals(required.namespace) && p.name.equals(required.name) && required.range.contains(p.version)); + } + + @Override + public String toString() { + return id + "_" + version; + } +} diff --git a/src/support/lombok/eclipse/dependencies/model/Version.java b/src/support/lombok/eclipse/dependencies/model/Version.java new file mode 100644 index 00000000..0ebcf2ef --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/Version.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +public class Version { + private int major; + private int minor; + private int micro; + private String qualifier = ""; + + public static Version parse(String v) { + String[] parts = v.split("\\.", 4); + + Version version = new Version(); + version.major = Integer.parseInt(parts[0]); + if (parts.length > 1) { + version.minor = Integer.parseInt(parts[1]); + } + if (parts.length > 2) { + version.micro = Integer.parseInt(parts[2]); + } + if (parts.length > 3) { + version.qualifier = parts[3]; + } + return version; + } + + public int compareTo(Version other) { + int result = major - other.major; + if (result != 0) return result; + + result = minor - other.minor; + if (result != 0) return result; + + result = micro - other.micro; + if (result != 0) return result; + + return qualifier.compareTo(other.qualifier); + } + + @Override + public String toString() { + String result = major + "." + minor + "." + micro; + if (!qualifier.isEmpty()) result += "." + qualifier; + return result; + } +} diff --git a/src/support/lombok/eclipse/dependencies/model/VersionAdapter.java b/src/support/lombok/eclipse/dependencies/model/VersionAdapter.java new file mode 100644 index 00000000..3c0f0ca1 --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/VersionAdapter.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +public class VersionAdapter extends XmlAdapter { + + @Override + public Version unmarshal(String v) throws Exception { + return Version.parse(v); + } + + @Override + public String marshal(Version v) throws Exception { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/support/lombok/eclipse/dependencies/model/VersionRange.java b/src/support/lombok/eclipse/dependencies/model/VersionRange.java new file mode 100644 index 00000000..7dda2dce --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/VersionRange.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +public class VersionRange { + public static final VersionRange ALL = VersionRange.parse("0.0.0"); + + private Version min; + private Version max; + private boolean leftInclusive; + private boolean leftExclusive; + private boolean rightInclusive; + private boolean rightExclusive; + + public static VersionRange parse(String v) { + VersionRange versionRange = new VersionRange(); + versionRange.leftInclusive = v.startsWith("["); + versionRange.leftExclusive = v.startsWith("("); + versionRange.rightInclusive = v.endsWith("]"); + versionRange.rightExclusive = v.endsWith(")"); + + if (!versionRange.leftInclusive && !versionRange.leftExclusive) { + Version version = Version.parse(v); + versionRange.min = version; + versionRange.leftInclusive = true; + return versionRange; + } + + String[] parts = v.replaceAll("[\\[\\(\\)\\]]", "").split(","); + versionRange.min = Version.parse(parts[0]); + versionRange.max = Version.parse(parts[1]); + return versionRange; + } + + public boolean contains(Version version) { + if (min != null) { + int result = min.compareTo(version); + if (result > 0) return false; + if (result == 0 && !leftInclusive) return false; + } + if (max != null) { + int result = max.compareTo(version); + if (result < 0) return false; + if (result == 0 && !rightInclusive) return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (leftInclusive) sb.append("["); + if (leftExclusive) sb.append("("); + if (min != null) sb.append(min); + sb.append(","); + if (max != null) sb.append(max); + if (rightInclusive) sb.append("]"); + if (rightExclusive) sb.append(")"); + return sb.toString(); + } +} diff --git a/src/support/lombok/eclipse/dependencies/model/VersionRangeAdapter.java b/src/support/lombok/eclipse/dependencies/model/VersionRangeAdapter.java new file mode 100644 index 00000000..43331817 --- /dev/null +++ b/src/support/lombok/eclipse/dependencies/model/VersionRangeAdapter.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.dependencies.model; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +public class VersionRangeAdapter extends XmlAdapter { + + @Override + public VersionRange unmarshal(String v) throws Exception { + return VersionRange.parse(v); + } + + @Override + public String marshal(VersionRange v) throws Exception { + throw new UnsupportedOperationException(); + } + +} diff --git a/test/bytecode/resource/PostCompilePreventNullAnalysis.java b/test/bytecode/resource/PostCompilePreventNullAnalysis.java new file mode 100644 index 00000000..0c9b387b --- /dev/null +++ b/test/bytecode/resource/PostCompilePreventNullAnalysis.java @@ -0,0 +1,15 @@ +public class PostCompilePreventNullAnalysis { + public void test() { + Object o = "Hello World!"; + try { + System.out.println(o); + } finally { + if (o != null) { + if (lombok.Lombok.preventNullAnalysis(o) != null) { + o.toString(); + } + } + } + } + +} diff --git a/test/bytecode/src/lombok/bytecode/TestPostCompiler.java b/test/bytecode/src/lombok/bytecode/TestPostCompiler.java index 2704ecec..3814e00d 100644 --- a/test/bytecode/src/lombok/bytecode/TestPostCompiler.java +++ b/test/bytecode/src/lombok/bytecode/TestPostCompiler.java @@ -33,7 +33,7 @@ import org.junit.Test; public class TestPostCompiler { @Test - public void testPostCompiler() throws IOException { + public void testPostCompilerSneakyThrows() { byte[] compiled = TestClassFileMetaData.compile(new File("test/bytecode/resource/PostCompileSneaky.java")); DiagnosticsReceiver receiver = new DiagnosticsReceiver() { @Override public void addWarning(String message) { @@ -50,5 +50,31 @@ public class TestPostCompiler { assertNotSame("Post-compiler did not do anything; we expected it to remove a Lombok.sneakyThrow() call.", compiled, transformed); assertTrue("After removing a sneakyThrow the classfile got... bigger (or stayed equal in size). Huh?", transformed.length < compiled.length); + + assertFalse("After post compilation, expected no lombok.Lombok.sneakyThrow() call in compiled code, but it's there", + new ClassFileMetaData(transformed).usesMethod("lombok/Lombok", "sneakyThrow")); + } + + @Test + public void testPostCompilerPreventNullAnalysis() { + byte[] compiled = TestClassFileMetaData.compile(new File("test/bytecode/resource/PostCompilePreventNullAnalysis.java")); + DiagnosticsReceiver receiver = new DiagnosticsReceiver() { + @Override public void addWarning(String message) { + fail("Warning during post compilation processing of a sneakyThrow call: " + message); + } + + @Override public void addError(String message) { + fail("Error during post compilation processing of a sneakyThrow call: " + message); + } + }; + assertTrue("Before post compilation, expected lombok.Lombok.preventNullAnalysis() call in compiled code, but it's not there", + new ClassFileMetaData(compiled).usesMethod("lombok/Lombok", "preventNullAnalysis")); + byte[] transformed = PostCompiler.applyTransformations(compiled, "PostCompilePreventNullAnalysis.java", receiver); + + assertNotSame("Post-compiler did not do anything; we expected it to remove a Lombok.preventNullAnalysis() call.", compiled, transformed); + assertTrue("After removing a sneakyThrow the classfile got... bigger (or stayed equal in size). Huh?", transformed.length < compiled.length); + + assertFalse("After post compilation, expected no lombok.Lombok.preventNullAnalysis() call in compiled code, but it's there", + new ClassFileMetaData(transformed).usesMethod("lombok/Lombok", "preventNullAnalysis")); } } diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index 51ec41c5..0cb379ff 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -29,14 +29,12 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; -import java.io.StringWriter; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import org.junit.Assert; @@ -83,28 +81,38 @@ public abstract class AbstractRunTests { return new FileTester() { @Override public void runTest() throws Throwable { if (directiveFailure_ != null) throw directiveFailure_; - LinkedHashSet messages = new LinkedHashSet(); - StringWriter writer = new StringWriter(); - LombokConfiguration.overrideConfigurationResolverFactory(new ConfigurationResolverFactory() { @Override public ConfigurationResolver createResolver(URI sourceLocation) { return sourceDirectives_.getConfiguration(); } }); + TestParameters testParameters = new TestParameters(); + testParameters.setEncoding(sourceDirectives_.getSpecifiedEncoding()); + testParameters.setFormatPreferences(sourceDirectives_.getFormatPreferences()); + testParameters.setMinVersion(sourceDirectives_.minVersion()); + testParameters.setVerifyDiet(sourceDirectives_.isVerifyDiet()); boolean checkPositions = !(params instanceof TestLombokFilesIdempotent || params instanceof TestSourceFiles) && !sourceDirectives_.isSkipCompareContent(); + testParameters.setCheckPositions(checkPositions); + String javaVersionString = System.getProperty("compiler.compliance.level"); + if (javaVersionString != null) { + long version = Long.parseLong(javaVersionString); + testParameters.setSourceVersion(version); + testParameters.setTargetVersion(version); + } - boolean changed = transformCode(messages, writer, file, sourceDirectives_.getSpecifiedEncoding(), sourceDirectives_.getFormatPreferences(), sourceDirectives_.minVersion(), checkPositions); + TransformationResult result = transformCode(file, testParameters); + boolean changed = result.isChanged(); 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")); + if (params.expectChanges() && !forceUnchanged && !changed) result.addMessage(new CompilerMessage(-1, -1, true, "not flagged modified")); + if (!params.expectChanges() && changed) result.addMessage(new CompilerMessage(-1, -1, true, "unexpected modification")); - compare(file.getName(), expected, writer.toString(), messages, params.printErrors(), sourceDirectives_.isSkipCompareContent() || expected.isSkipCompareContent()); + compare(file.getName(), expected, result, params.printErrors(), sourceDirectives_.isSkipCompareContent() || expected.isSkipCompareContent()); } }; } - protected abstract boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences, int minVersion, boolean checkPositions) throws Throwable; + protected abstract TransformationResult transformCode(File file, TestParameters parameters) throws Throwable; protected String readFile(File file) throws IOException { BufferedReader reader; @@ -154,7 +162,10 @@ public abstract class AbstractRunTests { } } - private void compare(String name, LombokTestSource expected, String actualFile, LinkedHashSet actualMessages, boolean printErrors, boolean skipCompareContent) throws Throwable { + private void compare(String name, LombokTestSource expected, TransformationResult result, boolean printErrors, boolean skipCompareContent) throws Throwable { + String actualFile = result.getOutput(); + LinkedHashSet actualMessages = result.getMessages(); + if (!skipCompareContent) try { compareContent(name, expected.getContent(), actualFile); } catch (Throwable e) { diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index 27ffc31a..92bc53ea 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2019 The Project Lombok Authors. + * Copyright (C) 2014-2024 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 @@ -58,6 +58,7 @@ public class LombokTestSource { private final boolean skipCompareContent; private final boolean skipIdempotent; private final boolean unchanged; + private final boolean verifyDiet; private final int versionLowerLimit, versionUpperLimit; private final ConfigurationResolver configuration; private final String specifiedEncoding; @@ -113,6 +114,10 @@ public class LombokTestSource { return skipIdempotent; } + public boolean isVerifyDiet() { + return verifyDiet; + } + public String getSpecifiedEncoding() { return specifiedEncoding; } @@ -162,6 +167,7 @@ public class LombokTestSource { private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?contents?\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern SKIP_IDEMPOTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?idempotent\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern ISSUE_REF_PATTERN = Pattern.compile("^\\s*issue #?\\d+(:?\\s+.*)?$", Pattern.CASE_INSENSITIVE); + private static final Pattern VERIFY_DIET_PATTERN = Pattern.compile("^\\s*eclipse:\\s*verify[- ]?diet\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private LombokTestSource(File file, String content, List messages, List directives) { this.file = file; @@ -175,6 +181,7 @@ public class LombokTestSource { boolean skipCompareContent = false; boolean skipIdempotent = false; boolean unchanged = false; + boolean verifyDiet = false; String encoding = null; Map formats = new HashMap(); String[] platformLimit = null; @@ -204,6 +211,10 @@ public class LombokTestSource { if (ISSUE_REF_PATTERN.matcher(directive).matches()) { continue; } + if (VERIFY_DIET_PATTERN.matcher(directive).matches()) { + verifyDiet = true; + continue; + } if (lc.startsWith("platform ")) { String platformDesc = lc.substring("platform ".length()); @@ -257,6 +268,7 @@ public class LombokTestSource { this.skipCompareContent = skipCompareContent; this.skipIdempotent = skipIdempotent; this.unchanged = unchanged; + this.verifyDiet = verifyDiet; this.platforms = platformLimit == null ? null : Arrays.asList(platformLimit); ConfigurationProblemReporter reporter = new ConfigurationProblemReporter() { diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java index adfb1fce..918a0de4 100644 --- a/test/core/src/lombok/RunTestsViaDelombok.java +++ b/test/core/src/lombok/RunTestsViaDelombok.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -66,24 +66,24 @@ import com.sun.tools.javac.tree.TreeScanner; import lombok.delombok.Delombok; import lombok.javac.CapturingDiagnosticListener; -import lombok.javac.CapturingDiagnosticListener.CompilerMessage; import lombok.javac.Javac; 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, int version, boolean checkPositions) throws Throwable { + public TransformationResult transformCode(final File file, TestParameters parameters) throws Throwable { + TransformationResult result = new TransformationResult(); delombok.setVerbose(true); ChangedChecker cc = new ChangedChecker(); delombok.setFeedback(cc.feedback); delombok.setForceProcess(true); - delombok.setCharset(encoding == null ? "UTF-8" : encoding); - delombok.setFormatPreferences(formatPreferences); + delombok.setCharset(parameters.getEncoding() == null ? "UTF-8" : parameters.getEncoding()); + delombok.setFormatPreferences(parameters.getFormatPreferences()); - delombok.setDiagnosticsListener(new CapturingDiagnosticListener(file, messages)); + delombok.setDiagnosticsListener(new CapturingDiagnosticListener(file, result.getMessages())); - if (checkPositions) delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(version)); + if (parameters.isCheckPositions()) delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(parameters.getMinVersion())); delombok.addAdditionalAnnotationProcessor(new ValidateTypesProcessor()); delombok.addAdditionalAnnotationProcessor(new ValidateNoDuplicateTreeNodeProcessor()); @@ -91,12 +91,15 @@ public class RunTestsViaDelombok extends AbstractRunTests { delombok.setSourcepath(file.getAbsoluteFile().getParent()); String bcp = System.getProperty("delombok.bootclasspath"); if (bcp != null) delombok.setBootclasspath(bcp); - delombok.setWriter(result); + StringWriter sw = new StringWriter(); + delombok.setWriter(sw); Locale originalLocale = Locale.getDefault(); try { Locale.setDefault(Locale.ENGLISH); delombok.delombok(); - return cc.isChanged(); + result.setOutput(sw.toString()); + result.setChanged(cc.isChanged()); + return result; } finally { Locale.setDefault(originalLocale); } diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index d46a890f..352ba4e6 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2021 The Project Lombok Authors. + * Copyright (C) 2010-2024 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,9 +22,7 @@ package lombok; import java.io.File; -import java.io.StringWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -32,9 +30,6 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import lombok.eclipse.Eclipse; -import lombok.javac.CapturingDiagnosticListener.CompilerMessage; - import org.eclipse.core.internal.registry.ExtensionRegistry; import org.eclipse.core.internal.runtime.Activator; import org.eclipse.core.internal.runtime.PlatformActivator; @@ -57,22 +52,24 @@ import org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; +import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner; import org.eclipse.jdt.internal.core.JavaModelManager; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import lombok.eclipse.Eclipse; +import lombok.javac.CapturingDiagnosticListener.CompilerMessage; + public class RunTestsViaEcj extends AbstractRunTests { - protected CompilerOptions ecjCompilerOptions() { + protected CompilerOptions ecjCompilerOptions(TestParameters parameters) { CompilerOptions options = new CompilerOptions(); Map warnings = new HashMap(); - String javaVersionString = System.getProperty("compiler.compliance.level"); long ecjCompilerVersionConstant = Eclipse.getLatestEcjCompilerVersionConstant(); long ecjCompilerVersion = Eclipse.getEcjCompilerVersion(); - if (javaVersionString != null) { - long javaVersion = Long.parseLong(javaVersionString); - ecjCompilerVersionConstant = (javaVersion + 44) << 16; - ecjCompilerVersion = javaVersion; + if (parameters.getSourceVersion() != null) { + ecjCompilerVersionConstant = (parameters.getSourceVersion() + 44) << 16; + ecjCompilerVersion = parameters.getSourceVersion(); } else { // Preview features are only allowed if the maximum compiler version is equal to the source version warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled"); @@ -127,7 +124,8 @@ public class RunTestsViaEcj extends AbstractRunTests { } @Override - public boolean transformCode(Collection messages, StringWriter result, File file, String encoding, Map formatPreferences, int minVersion, boolean checkPositions) throws Throwable { + public TransformationResult transformCode(File file, final TestParameters parameters) throws Throwable { + final TransformationResult result = new TransformationResult(); final AtomicReference compilationResult_ = new AtomicReference(); final AtomicReference compilationUnit_ = new AtomicReference(); ICompilerRequestor bitbucketRequestor = new ICompilerRequestor() { @@ -143,12 +141,18 @@ public class RunTestsViaEcj extends AbstractRunTests { sourceUnit = getSourceUnit(file, source); } catch (Throwable t) { t.printStackTrace(); - return false; + result.setChanged(false); + return result; } - Compiler ecjCompiler = new Compiler(createFileSystem(file, minVersion), ecjErrorHandlingPolicy(), ecjCompilerOptions(), bitbucketRequestor, new DefaultProblemFactory(Locale.ENGLISH)) { + Compiler ecjCompiler = new Compiler(createFileSystem(file), ecjErrorHandlingPolicy(), ecjCompilerOptions(parameters), bitbucketRequestor, new DefaultProblemFactory(Locale.ENGLISH)) { @Override protected synchronized void addCompilationUnit(ICompilationUnit inUnit, CompilationUnitDeclaration parsedUnit) { - if (inUnit == sourceUnit) compilationUnit_.set(parsedUnit); + if (inUnit == sourceUnit) { + compilationUnit_.set(parsedUnit); + if (parameters.isVerifyDiet()) { + result.setOutput(parsedUnit.toString()); + } + } super.addCompilationUnit(inUnit, parsedUnit); } }; @@ -161,24 +165,28 @@ public class RunTestsViaEcj extends AbstractRunTests { CategorizedProblem[] problems = compilationResult.getAllProblems(); if (problems != null) for (CategorizedProblem p : problems) { - messages.add(new CompilerMessage(p.getSourceLineNumber(), p.getSourceStart(), p.isError(), p.getMessage())); + result.addMessage(new CompilerMessage(p.getSourceLineNumber(), p.getSourceStart(), p.isError(), p.getMessage())); } CompilationUnitDeclaration cud = compilationUnit_.get(); - if (cud == null) result.append("---- No CompilationUnit provided by ecj ----"); - else { - String output = cud.toString(); - // starting somewhere around ecj16, the print code is a bit too cavalier with printing modifiers. - output = output.replace("non-sealed @val", "@val"); - result.append(output); + if (cud == null) { + result.setOutput("---- No CompilationUnit provided by ecj ----"); + } else { + if (!parameters.isVerifyDiet()) { + String output = cud.toString(); + // starting somewhere around ecj16, the print code is a bit too cavalier with printing modifiers. + output = output.replace("non-sealed @val", "@val"); + result.setOutput(output); + } + + if (eclipseAvailable()) { + EclipseDomConversion.toDomAst(cud, sourceArray); + } } - if (eclipseAvailable()) { - EclipseDomConversion.toDomAst(cud, sourceArray); - } - - return true; + result.setChanged(true); + return result; } @SuppressWarnings("unused") @@ -238,7 +246,7 @@ public class RunTestsViaEcj extends AbstractRunTests { } } - private FileSystem createFileSystem(File file, int minVersion) { + private FileSystem createFileSystem(File file) { List classpath = new ArrayList(); if (new File("bin/main").exists()) classpath.add("bin/main"); classpath.add("dist/lombok.jar"); @@ -301,7 +309,7 @@ public class RunTestsViaEcj extends AbstractRunTests { private final char[] mainTypeName; private TestCompilationUnitEclipse(String name, String source) { - super(null, name, null); + super(null, name, DefaultWorkingCopyOwner.PRIMARY); this.source = source.toCharArray(); char[] fileNameCharArray = getFileName(); @@ -313,14 +321,6 @@ public class RunTestsViaEcj extends AbstractRunTests { mainTypeName = CharOperation.subarray(fileNameCharArray, start, end); } - @Override public int hashCode() { - return System.identityHashCode(this); - } - - @Override public boolean equals(Object obj) { - return this == obj; - } - @Override public char[] getContents() { return source; } diff --git a/test/core/src/lombok/TestParameters.java b/test/core/src/lombok/TestParameters.java new file mode 100644 index 00000000..dba7b990 --- /dev/null +++ b/test/core/src/lombok/TestParameters.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok; + +import java.util.Map; + +public class TestParameters { + private Long sourceVersion; + private Long targetVersion; + + // Javac only + private Integer minVersion; + private String encoding; + private Map formatPreferences; + private boolean checkPositions; + + // Eclipse/Ecj only + private boolean verifyDiet; + + public Long getSourceVersion() { + return sourceVersion; + } + + public void setSourceVersion(Long sourceVersion) { + this.sourceVersion = sourceVersion; + } + + public Long getTargetVersion() { + return targetVersion; + } + + public void setTargetVersion(Long targetVersion) { + this.targetVersion = targetVersion; + } + + public Integer getMinVersion() { + return minVersion; + } + + public void setMinVersion(Integer minVersion) { + this.minVersion = minVersion; + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public Map getFormatPreferences() { + return formatPreferences; + } + + public void setFormatPreferences(Map formatPreferences) { + this.formatPreferences = formatPreferences; + } + + public boolean isCheckPositions() { + return checkPositions; + } + + public void setCheckPositions(boolean checkPositions) { + this.checkPositions = checkPositions; + } + + public boolean isVerifyDiet() { + return verifyDiet; + } + + public void setVerifyDiet(boolean verifyDiet) { + this.verifyDiet = verifyDiet; + } +} diff --git a/test/core/src/lombok/TransformationResult.java b/test/core/src/lombok/TransformationResult.java new file mode 100644 index 00000000..b0d45e44 --- /dev/null +++ b/test/core/src/lombok/TransformationResult.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok; + +import java.util.LinkedHashSet; + +import lombok.javac.CapturingDiagnosticListener.CompilerMessage; + +public class TransformationResult { + private boolean changed; + private boolean success; + private LinkedHashSet messages = new LinkedHashSet(); + private String output; + + public void addMessage(CompilerMessage message) { + getMessages().add(message); + } + + public void setOutput(String output) { + this.output = output; + } + + public String getOutput() { + return output; + } + + public boolean isChanged() { + return changed; + } + + public void setChanged(boolean changed) { + this.changed = changed; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public LinkedHashSet getMessages() { + return messages; + } +} diff --git a/test/eclipse/resource/delegate/model/DelegateModel.java b/test/eclipse/resource/delegate/model/DelegateModel.java new file mode 100644 index 00000000..4c1700e9 --- /dev/null +++ b/test/eclipse/resource/delegate/model/DelegateModel.java @@ -0,0 +1,9 @@ +package pkg; + +import lombok.experimental.Delegate; + +public class DelegateModel { + + @Delegate + private Runnable run; +} \ No newline at end of file diff --git a/test/eclipse/resource/javadoc/getterSetter/Javadoc.java b/test/eclipse/resource/javadoc/getterSetter/Javadoc.java new file mode 100644 index 00000000..9f07e9e0 --- /dev/null +++ b/test/eclipse/resource/javadoc/getterSetter/Javadoc.java @@ -0,0 +1,25 @@ +package pkg; + +import lombok.Getter; +import lombok.Setter; + +public class Javadoc { + /** + * Some text + * + * **SETTER** + * Setter section + * @param fieldName Hello, World3 + * **GETTER** + * Getter section + * @return Sky is blue3 + */ + @Getter + @Setter + private int field; + + public void usage() { + getField(); + setField(0); + } +} \ No newline at end of file diff --git a/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Annotation.java b/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Annotation.java new file mode 100644 index 00000000..e3ecb40f --- /dev/null +++ b/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Annotation.java @@ -0,0 +1,5 @@ +package pkg; + +public @interface Annotation { + String value(); +} \ No newline at end of file diff --git a/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Constants.java b/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Constants.java new file mode 100644 index 00000000..fad3811f --- /dev/null +++ b/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Constants.java @@ -0,0 +1,8 @@ +package pkg; + +import lombok.experimental.FieldNameConstants; + +@FieldNameConstants +public class Constants { + String test; +} \ No newline at end of file diff --git a/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Usage.java b/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Usage.java new file mode 100644 index 00000000..5f8880ef --- /dev/null +++ b/test/eclipse/resource/noerrors/fieldNameConstantsInAnnotation/Usage.java @@ -0,0 +1,5 @@ +package pkg; + +@Annotation(Constants.Fields.test) +public class Usage { +} \ No newline at end of file diff --git a/test/eclipse/src/lombok/eclipse/EclipseRunner.java b/test/eclipse/src/lombok/eclipse/EclipseRunner.java index 1e1c17fe..36e98d9e 100644 --- a/test/eclipse/src/lombok/eclipse/EclipseRunner.java +++ b/test/eclipse/src/lombok/eclipse/EclipseRunner.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse; import java.io.File; diff --git a/test/eclipse/src/lombok/eclipse/EclipseTests.java b/test/eclipse/src/lombok/eclipse/EclipseTests.java index 5fba9903..66f5d9fa 100644 --- a/test/eclipse/src/lombok/eclipse/EclipseTests.java +++ b/test/eclipse/src/lombok/eclipse/EclipseTests.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022-2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse; import org.junit.runner.RunWith; @@ -5,14 +26,17 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; import lombok.eclipse.cleanup.CleanupTest; +import lombok.eclipse.compile.NoErrorsTest; import lombok.eclipse.edit.SelectTest; +import lombok.eclipse.misc.DelegateTest; +import lombok.eclipse.misc.JavadocTest; import lombok.eclipse.refactoring.ExtractInterfaceTest; import lombok.eclipse.refactoring.InlineTest; import lombok.eclipse.refactoring.RenameTest; import lombok.eclipse.references.FindReferencesTest; @RunWith(Suite.class) -@SuiteClasses({ExtractInterfaceTest.class, RenameTest.class, SelectTest.class, CleanupTest.class, FindReferencesTest.class, InlineTest.class}) +@SuiteClasses({ExtractInterfaceTest.class, RenameTest.class, SelectTest.class, CleanupTest.class, FindReferencesTest.class, InlineTest.class, NoErrorsTest.class, JavadocTest.class, DelegateTest.class}) public class EclipseTests { } diff --git a/test/eclipse/src/lombok/eclipse/RefactoringUtils.java b/test/eclipse/src/lombok/eclipse/RefactoringUtils.java index 38349d2d..2362ff11 100644 --- a/test/eclipse/src/lombok/eclipse/RefactoringUtils.java +++ b/test/eclipse/src/lombok/eclipse/RefactoringUtils.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse; import static org.junit.Assert.assertTrue; diff --git a/test/eclipse/src/lombok/eclipse/SetupBeforeAfterTest.java b/test/eclipse/src/lombok/eclipse/SetupBeforeAfterTest.java index 05deabde..ff51ef13 100644 --- a/test/eclipse/src/lombok/eclipse/SetupBeforeAfterTest.java +++ b/test/eclipse/src/lombok/eclipse/SetupBeforeAfterTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022-2023 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse; import static org.junit.Assert.assertEquals; diff --git a/test/eclipse/src/lombok/eclipse/SetupSingleFileTest.java b/test/eclipse/src/lombok/eclipse/SetupSingleFileTest.java index 47010f0c..d4b934ce 100644 --- a/test/eclipse/src/lombok/eclipse/SetupSingleFileTest.java +++ b/test/eclipse/src/lombok/eclipse/SetupSingleFileTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse; import java.io.File; diff --git a/test/eclipse/src/lombok/eclipse/SetupTest.java b/test/eclipse/src/lombok/eclipse/SetupTest.java index fe8d469c..d3a2f1b0 100644 --- a/test/eclipse/src/lombok/eclipse/SetupTest.java +++ b/test/eclipse/src/lombok/eclipse/SetupTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse; import java.io.File; diff --git a/test/eclipse/src/lombok/eclipse/cleanup/CleanupTest.java b/test/eclipse/src/lombok/eclipse/cleanup/CleanupTest.java index 2d018228..76956aff 100644 --- a/test/eclipse/src/lombok/eclipse/cleanup/CleanupTest.java +++ b/test/eclipse/src/lombok/eclipse/cleanup/CleanupTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse.cleanup; import static lombok.eclipse.RefactoringUtils.performRefactoring; diff --git a/test/eclipse/src/lombok/eclipse/compile/NoErrorsTest.java b/test/eclipse/src/lombok/eclipse/compile/NoErrorsTest.java new file mode 100644 index 00000000..6d81d381 --- /dev/null +++ b/test/eclipse/src/lombok/eclipse/compile/NoErrorsTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.compile; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IProblemRequestor; +import org.eclipse.jdt.core.WorkingCopyOwner; +import org.eclipse.jdt.core.compiler.IProblem; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import lombok.eclipse.EclipseRunner; +import lombok.eclipse.SetupSingleFileTest; + +@RunWith(EclipseRunner.class) +public class NoErrorsTest { + + @Rule + public SetupSingleFileTest setup = new SetupSingleFileTest(); + + @Test + public void fieldNameConstantsInAnnotation() throws Exception { + ICompilationUnit cu = setup.getPackageFragment().getCompilationUnit("Usage.java"); + + final List problems = new ArrayList(); + final IProblemRequestor requestor = new IProblemRequestor() { + @Override + public void acceptProblem(IProblem problem) { + problems.add(problem); + } + + @Override + public void beginReporting() { + problems.clear(); + } + + @Override + public void endReporting() { + } + + @Override + public boolean isActive() { + return true; + } + }; + + WorkingCopyOwner workingCopyOwner = new WorkingCopyOwner() { + @Override + public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) { + return requestor; + } + }; + + ICompilationUnit workingCopy = cu.getWorkingCopy(workingCopyOwner, null); + try { + workingCopy.reconcile(ICompilationUnit.NO_AST, true, true, workingCopy.getOwner(), null); + } finally { + workingCopy.discardWorkingCopy(); + } + + System.out.println(problems); + assertTrue(problems.isEmpty()); + } +} diff --git a/test/eclipse/src/lombok/eclipse/edit/SelectTest.java b/test/eclipse/src/lombok/eclipse/edit/SelectTest.java index 9f348a0c..a9723618 100644 --- a/test/eclipse/src/lombok/eclipse/edit/SelectTest.java +++ b/test/eclipse/src/lombok/eclipse/edit/SelectTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse.edit; import static org.junit.Assert.assertEquals; diff --git a/test/eclipse/src/lombok/eclipse/misc/DelegateTest.java b/test/eclipse/src/lombok/eclipse/misc/DelegateTest.java new file mode 100644 index 00000000..899dc9f9 --- /dev/null +++ b/test/eclipse/src/lombok/eclipse/misc/DelegateTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.misc; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.WorkingCopyOwner; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import lombok.eclipse.EclipseRunner; +import lombok.eclipse.SetupSingleFileTest; + +@RunWith(EclipseRunner.class) +public class DelegateTest { + + @Rule + public SetupSingleFileTest setup = new SetupSingleFileTest(); + + @Test + public void model() throws Exception { + ICompilationUnit cu = setup.getPackageFragment().getCompilationUnit("DelegateModel.java"); + + WorkingCopyOwner workingCopyOwner = new WorkingCopyOwner() {}; + ICompilationUnit workingCopy = cu.getWorkingCopy(workingCopyOwner, null); + try { + workingCopy.reconcile(ICompilationUnit.NO_AST, true, true, workingCopy.getOwner(), null); + + assertThat(workingCopy.findPrimaryType().getMethods().length, is(not(0))); + + IMethod runMethod = workingCopy.findPrimaryType().getMethods()[0]; + assertEquals(runMethod.getElementName(), "run"); + + ISourceRange sourceRange = runMethod.getSourceRange(); + assertNotNull(sourceRange); + assertEquals(sourceRange.getOffset(), 84); + assertEquals(sourceRange.getLength(), 9); + } finally { + workingCopy.discardWorkingCopy(); + } + } +} diff --git a/test/eclipse/src/lombok/eclipse/misc/JavadocTest.java b/test/eclipse/src/lombok/eclipse/misc/JavadocTest.java new file mode 100644 index 00000000..fd7a5daa --- /dev/null +++ b/test/eclipse/src/lombok/eclipse/misc/JavadocTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.misc; + +import static org.junit.Assert.assertThat; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2; +import org.hamcrest.CoreMatchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import lombok.eclipse.EclipseRunner; +import lombok.eclipse.SetupSingleFileTest; + +@RunWith(EclipseRunner.class) +public class JavadocTest { + + @Rule + public SetupSingleFileTest setup = new SetupSingleFileTest(); + + @Test + public void getterSetter() throws Exception { + ICompilationUnit cu = setup.getPackageFragment().getCompilationUnit("Javadoc.java"); + + IJavaElement getterInvocation = cu.codeSelect(306, 0)[0]; + String getterHtmlContent = JavadocContentAccess2.getHTMLContent(getterInvocation, true); + assertThat(getterHtmlContent, CoreMatchers.containsString("Getter section")); + assertThat(getterHtmlContent, CoreMatchers.containsString("Returns:")); + assertThat(getterHtmlContent, CoreMatchers.containsString("Sky is blue3")); + + IJavaElement setterInvocation = cu.codeSelect(320, 0)[0]; + String setterHtmlContent = JavadocContentAccess2.getHTMLContent(setterInvocation, true); + assertThat(setterHtmlContent, CoreMatchers.containsString("Setter section")); + assertThat(setterHtmlContent, CoreMatchers.containsString("Parameters:")); + assertThat(setterHtmlContent, CoreMatchers.containsString("fieldName")); + assertThat(setterHtmlContent, CoreMatchers.containsString("Hello, World3")); + assertThat(setterHtmlContent, CoreMatchers.containsString("field")); + } +} diff --git a/test/eclipse/src/lombok/eclipse/refactoring/ExtractInterfaceTest.java b/test/eclipse/src/lombok/eclipse/refactoring/ExtractInterfaceTest.java index d4c892f3..1ad64398 100644 --- a/test/eclipse/src/lombok/eclipse/refactoring/ExtractInterfaceTest.java +++ b/test/eclipse/src/lombok/eclipse/refactoring/ExtractInterfaceTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse.refactoring; import static lombok.eclipse.RefactoringUtils.performRefactoring; diff --git a/test/eclipse/src/lombok/eclipse/refactoring/InlineTest.java b/test/eclipse/src/lombok/eclipse/refactoring/InlineTest.java index 1a3315b7..25a21d62 100644 --- a/test/eclipse/src/lombok/eclipse/refactoring/InlineTest.java +++ b/test/eclipse/src/lombok/eclipse/refactoring/InlineTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2023 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse.refactoring; import static lombok.eclipse.RefactoringUtils.performRefactoring; diff --git a/test/eclipse/src/lombok/eclipse/refactoring/RenameTest.java b/test/eclipse/src/lombok/eclipse/refactoring/RenameTest.java index 8ce4874c..7f085f08 100644 --- a/test/eclipse/src/lombok/eclipse/refactoring/RenameTest.java +++ b/test/eclipse/src/lombok/eclipse/refactoring/RenameTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2022-2023 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse.refactoring; import static lombok.eclipse.RefactoringUtils.performRefactoring; diff --git a/test/eclipse/src/lombok/eclipse/references/FindReferencesTest.java b/test/eclipse/src/lombok/eclipse/references/FindReferencesTest.java index a4668088..e2806ea3 100644 --- a/test/eclipse/src/lombok/eclipse/references/FindReferencesTest.java +++ b/test/eclipse/src/lombok/eclipse/references/FindReferencesTest.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2023 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.eclipse.references; import static org.junit.Assert.*; diff --git a/test/pretty/resource/after/UnnamedVariables.java b/test/pretty/resource/after/UnnamedVariables.java new file mode 100644 index 00000000..f95b29ca --- /dev/null +++ b/test/pretty/resource/after/UnnamedVariables.java @@ -0,0 +1,70 @@ +// version 22: +import java.util.Arrays; +import java.util.Scanner; +import java.util.stream.Stream; + +record Box(T content) { +} + +record Pair(T first, U second) { +} + +public class UnnamedVariables { + void enhancedLoop() { + for (String _ : Arrays.asList("")) { + } + } + + void initializationInForLoop() { + for (int i = 0, _ = Integer.MAX_VALUE; i < 10; i++) { + } + } + + void assignment() { + var _ = 1; + } + + void catchBlock() { + try { + } catch (Exception _) { + } + } + + void tryWithResources() { + try (var _ = new Scanner("")) { + } + } + + void lambda() { + Stream.of(1).forEach(_ -> { + }); + } + + Object switchStatement(Object o) { + return switch (o) { + case String _, Integer _ -> o; + case Long _ -> o; + default -> o; + }; + } + + void recordPattern(Object o) { + if (o instanceof Pair(Box _, Box(Integer _))) { + } + if (o instanceof Box(String _)) { + } + if (o instanceof Box(var _)) { + } + if (o instanceof Box(_)) { + } + } + + Object recordPatternSwitch(Object o) { + return switch (o) { + case Box(String _), Box(Integer _) -> o; + case Box(Long _) -> o; + case Box(_) -> o; + default -> o; + }; + } +} diff --git a/test/pretty/resource/before/UnnamedVariables.java b/test/pretty/resource/before/UnnamedVariables.java new file mode 100644 index 00000000..f95b29ca --- /dev/null +++ b/test/pretty/resource/before/UnnamedVariables.java @@ -0,0 +1,70 @@ +// version 22: +import java.util.Arrays; +import java.util.Scanner; +import java.util.stream.Stream; + +record Box(T content) { +} + +record Pair(T first, U second) { +} + +public class UnnamedVariables { + void enhancedLoop() { + for (String _ : Arrays.asList("")) { + } + } + + void initializationInForLoop() { + for (int i = 0, _ = Integer.MAX_VALUE; i < 10; i++) { + } + } + + void assignment() { + var _ = 1; + } + + void catchBlock() { + try { + } catch (Exception _) { + } + } + + void tryWithResources() { + try (var _ = new Scanner("")) { + } + } + + void lambda() { + Stream.of(1).forEach(_ -> { + }); + } + + Object switchStatement(Object o) { + return switch (o) { + case String _, Integer _ -> o; + case Long _ -> o; + default -> o; + }; + } + + void recordPattern(Object o) { + if (o instanceof Pair(Box _, Box(Integer _))) { + } + if (o instanceof Box(String _)) { + } + if (o instanceof Box(var _)) { + } + if (o instanceof Box(_)) { + } + } + + Object recordPatternSwitch(Object o) { + return switch (o) { + case Box(String _), Box(Integer _) -> o; + case Box(Long _) -> o; + case Box(_) -> o; + default -> o; + }; + } +} diff --git a/test/transform/resource/after-delombok/BuilderOnNestedClass.java b/test/transform/resource/after-delombok/BuilderOnNestedClass.java new file mode 100644 index 00000000..76e69f78 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderOnNestedClass.java @@ -0,0 +1,49 @@ +public class BuilderOnNestedClass { + private T t; + + + public static class Nested { + private String a; + + @java.lang.SuppressWarnings("all") + Nested(final String a) { + this.a = a; + } + + + @java.lang.SuppressWarnings("all") + public static class NestedBuilder { + @java.lang.SuppressWarnings("all") + private String a; + + @java.lang.SuppressWarnings("all") + NestedBuilder() { + } + + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderOnNestedClass.Nested.NestedBuilder a(final String a) { + this.a = a; + return this; + } + + @java.lang.SuppressWarnings("all") + public BuilderOnNestedClass.Nested build() { + return new BuilderOnNestedClass.Nested(this.a); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderOnNestedClass.Nested.NestedBuilder(a=" + this.a + ")"; + } + } + + @java.lang.SuppressWarnings("all") + public static BuilderOnNestedClass.Nested.NestedBuilder builder() { + return new BuilderOnNestedClass.Nested.NestedBuilder(); + } + } +} diff --git a/test/transform/resource/after-delombok/BuilderOnNestedRecord.java b/test/transform/resource/after-delombok/BuilderOnNestedRecord.java new file mode 100644 index 00000000..83de7e06 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderOnNestedRecord.java @@ -0,0 +1,41 @@ +// version 14: +public record BuilderOnNestedRecord(T t) { + + public record Nested(String a) { + + @java.lang.SuppressWarnings("all") + public static class NestedBuilder { + @java.lang.SuppressWarnings("all") + private String a; + + @java.lang.SuppressWarnings("all") + NestedBuilder() { + } + + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderOnNestedRecord.Nested.NestedBuilder a(final String a) { + this.a = a; + return this; + } + + @java.lang.SuppressWarnings("all") + public BuilderOnNestedRecord.Nested build() { + return new BuilderOnNestedRecord.Nested(this.a); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderOnNestedRecord.Nested.NestedBuilder(a=" + this.a + ")"; + } + } + + @java.lang.SuppressWarnings("all") + public static BuilderOnNestedRecord.Nested.NestedBuilder builder() { + return new BuilderOnNestedRecord.Nested.NestedBuilder(); + } + } +} diff --git a/test/transform/resource/after-delombok/DelegateOnGetter.java b/test/transform/resource/after-delombok/DelegateOnGetter.java index edf1641b..76794085 100644 --- a/test/transform/resource/after-delombok/DelegateOnGetter.java +++ b/test/transform/resource/after-delombok/DelegateOnGetter.java @@ -6,11 +6,11 @@ class DelegateOnGetter { } @java.lang.SuppressWarnings({"all", "unchecked"}) public Bar getBar() { - java.lang.Object value = this.bar.get(); - if (value == null) { + java.lang.Object $value = this.bar.get(); + if ($value == null) { synchronized (this.bar) { - value = this.bar.get(); - if (value == null) { + $value = this.bar.get(); + if ($value == null) { final Bar actualValue = new Bar() { public void setList(java.util.ArrayList list) { } @@ -18,12 +18,12 @@ class DelegateOnGetter { return 42; } }; - value = actualValue == null ? this.bar : actualValue; - this.bar.set(value); + $value = actualValue == null ? this.bar : actualValue; + this.bar.set($value); } } } - return (Bar) (value == this.bar ? null : value); + return (Bar) ($value == this.bar ? null : $value); } @java.lang.SuppressWarnings("all") public void setList(final java.util.ArrayList list) { diff --git a/test/transform/resource/after-delombok/ExtensionMethodAmbiguousFunctional.java b/test/transform/resource/after-delombok/ExtensionMethodAmbiguousFunctional.java new file mode 100644 index 00000000..8c93c03d --- /dev/null +++ b/test/transform/resource/after-delombok/ExtensionMethodAmbiguousFunctional.java @@ -0,0 +1,17 @@ +//skip-idempotent +import java.util.function.Consumer; +import java.util.function.Function; + +class ExtensionMethodAmbiguousFunctional { + public void test() { + ExtensionMethodAmbiguousFunctional.Extensions.ambiguous("", System.out::println); + } + + static class Extensions { + public static void ambiguous(T t, Function function) { + } + + public static void ambiguous(T t, Consumer function) { + } + } +} diff --git a/test/transform/resource/after-delombok/GetterLazy.java b/test/transform/resource/after-delombok/GetterLazy.java index 1e30f94b..8e1300be 100644 --- a/test/transform/resource/after-delombok/GetterLazy.java +++ b/test/transform/resource/after-delombok/GetterLazy.java @@ -4,17 +4,17 @@ class GetterLazy { private final java.util.concurrent.atomic.AtomicReference fieldName = new java.util.concurrent.atomic.AtomicReference(); @java.lang.SuppressWarnings({"all", "unchecked"}) public ValueType getFieldName() { - java.lang.Object value = this.fieldName.get(); - if (value == null) { + java.lang.Object $value = this.fieldName.get(); + if ($value == null) { synchronized (this.fieldName) { - value = this.fieldName.get(); - if (value == null) { + $value = this.fieldName.get(); + if ($value == null) { final ValueType actualValue = new ValueType(); - value = actualValue == null ? this.fieldName : actualValue; - this.fieldName.set(value); + $value = actualValue == null ? this.fieldName : actualValue; + this.fieldName.set($value); } } } - return (ValueType) (value == this.fieldName ? null : value); + return (ValueType) ($value == this.fieldName ? null : $value); } } diff --git a/test/transform/resource/after-delombok/GetterLazyArguments.java b/test/transform/resource/after-delombok/GetterLazyArguments.java index ef3f341c..00b17f5c 100644 --- a/test/transform/resource/after-delombok/GetterLazyArguments.java +++ b/test/transform/resource/after-delombok/GetterLazyArguments.java @@ -21,99 +21,99 @@ class GetterLazyArguments { @java.lang.SuppressWarnings({"all", "unchecked"}) public String getField1() { - java.lang.Object value = this.field1.get(); - if (value == null) { + java.lang.Object $value = this.field1.get(); + if ($value == null) { synchronized (this.field1) { - value = this.field1.get(); - if (value == null) { + $value = this.field1.get(); + if ($value == null) { final String actualValue = stringInt(("a"), (1)); - value = actualValue == null ? this.field1 : actualValue; - this.field1.set(value); + $value = actualValue == null ? this.field1 : actualValue; + this.field1.set($value); } } } - return (String) (value == this.field1 ? null : 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) { + java.lang.Object $value = this.field2.get(); + if ($value == null) { synchronized (this.field2) { - value = this.field2.get(); - if (value == null) { + $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); + $value = actualValue == null ? this.field2 : actualValue; + this.field2.set($value); } } } - return (String) (value == this.field2 ? null : 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) { + java.lang.Object $value = this.field3.get(); + if ($value == null) { synchronized (this.field3) { - value = this.field3.get(); - if (value == null) { + $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); + $value = actualValue == null ? this.field3 : actualValue; + this.field3.set($value); } } } - return (String) (value == this.field3 ? null : 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) { + java.lang.Object $value = this.field4.get(); + if ($value == null) { synchronized (this.field4) { - value = this.field4.get(); - if (value == null) { + $value = this.field4.get(); + if ($value == null) { final String actualValue = stringRunnable(fun(), () -> { }); - value = actualValue == null ? this.field4 : actualValue; - this.field4.set(value); + $value = actualValue == null ? this.field4 : actualValue; + this.field4.set($value); } } } - return (String) (value == this.field4 ? null : 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) { + java.lang.Object $value = this.field5.get(); + if ($value == null) { synchronized (this.field5) { - value = this.field5.get(); - if (value == null) { + $value = this.field5.get(); + if ($value == null) { final String actualValue = stringRunnable(("a"), () -> { }); - value = actualValue == null ? this.field5 : actualValue; - this.field5.set(value); + $value = actualValue == null ? this.field5 : actualValue; + this.field5.set($value); } } } - return (String) (value == this.field5 ? null : value); + return (String) ($value == this.field5 ? null : $value); } @java.lang.SuppressWarnings({"all", "unchecked"}) public String getField6() { - java.lang.Object value = this.field6.get(); - if (value == null) { + java.lang.Object $value = this.field6.get(); + if ($value == null) { synchronized (this.field6) { - value = this.field6.get(); - if (value == null) { + $value = this.field6.get(); + if ($value == null) { final String actualValue = true ? stringInt(true ? "a" : "b", true ? 1 : 0) : ""; - value = actualValue == null ? this.field6 : actualValue; - this.field6.set(value); + $value = actualValue == null ? this.field6 : actualValue; + this.field6.set($value); } } } - return (String) (value == this.field6 ? null : value); + return (String) ($value == this.field6 ? null : $value); } } \ No newline at end of file diff --git a/test/transform/resource/after-delombok/GetterLazyBoolean.java b/test/transform/resource/after-delombok/GetterLazyBoolean.java index 5b1f19dc..495e6b92 100644 --- a/test/transform/resource/after-delombok/GetterLazyBoolean.java +++ b/test/transform/resource/after-delombok/GetterLazyBoolean.java @@ -33,32 +33,32 @@ class GetterLazyBoolean { } @java.lang.SuppressWarnings({"all", "unchecked"}) public boolean isBooleanValue() { - java.lang.Object value = this.booleanValue.get(); - if (value == null) { + java.lang.Object $value = this.booleanValue.get(); + if ($value == null) { synchronized (this.booleanValue) { - value = this.booleanValue.get(); - if (value == null) { + $value = this.booleanValue.get(); + if ($value == null) { final boolean actualValue = calculateBoolean(); - value = actualValue; - this.booleanValue.set(value); + $value = actualValue; + this.booleanValue.set($value); } } } - return (java.lang.Boolean) value; + return (java.lang.Boolean) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public boolean isOtherBooleanValue() { - java.lang.Object value = this.otherBooleanValue.get(); - if (value == null) { + java.lang.Object $value = this.otherBooleanValue.get(); + if ($value == null) { synchronized (this.otherBooleanValue) { - value = this.otherBooleanValue.get(); - if (value == null) { + $value = this.otherBooleanValue.get(); + if ($value == null) { final boolean actualValue = !calculateBoolean(); - value = actualValue; - this.otherBooleanValue.set(value); + $value = actualValue; + this.otherBooleanValue.set($value); } } } - return (java.lang.Boolean) value; + return (java.lang.Boolean) $value; } } diff --git a/test/transform/resource/after-delombok/GetterLazyEahcToString.java b/test/transform/resource/after-delombok/GetterLazyEahcToString.java index bec89818..3742093b 100644 --- a/test/transform/resource/after-delombok/GetterLazyEahcToString.java +++ b/test/transform/resource/after-delombok/GetterLazyEahcToString.java @@ -46,18 +46,18 @@ class GetterLazyEahcToString { @java.lang.SuppressWarnings({"all", "unchecked"}) public String getValue() { - java.lang.Object value = this.value.get(); - if (value == null) { + java.lang.Object $value = this.value.get(); + if ($value == null) { synchronized (this.value) { - value = this.value.get(); - if (value == null) { + $value = this.value.get(); + if ($value == null) { final String actualValue = ""; - value = actualValue == null ? this.value : actualValue; - this.value.set(value); + $value = actualValue == null ? this.value : actualValue; + this.value.set($value); } } } - return (String) (value == this.value ? null : value); + return (String) ($value == this.value ? null : $value); } @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-delombok/GetterLazyErrorPosition.java b/test/transform/resource/after-delombok/GetterLazyErrorPosition.java index 76797d44..c9013876 100644 --- a/test/transform/resource/after-delombok/GetterLazyErrorPosition.java +++ b/test/transform/resource/after-delombok/GetterLazyErrorPosition.java @@ -3,17 +3,17 @@ class GetterLazyErrorPosition { @java.lang.SuppressWarnings({"all", "unchecked"}) public String getField() { - java.lang.Object value = this.field.get(); - if (value == null) { + java.lang.Object $value = this.field.get(); + if ($value == null) { synchronized (this.field) { - value = this.field.get(); - if (value == null) { + $value = this.field.get(); + if ($value == null) { final String actualValue = true ? "" : new ErrorPosition(); - value = actualValue == null ? this.field : actualValue; - this.field.set(value); + $value = actualValue == null ? this.field : actualValue; + this.field.set($value); } } } - return (String) (value == this.field ? null : value); + return (String) ($value == this.field ? null : $value); } } diff --git a/test/transform/resource/after-delombok/GetterLazyGenerics.java b/test/transform/resource/after-delombok/GetterLazyGenerics.java index 5e92cda7..a8b8ff6c 100644 --- a/test/transform/resource/after-delombok/GetterLazyGenerics.java +++ b/test/transform/resource/after-delombok/GetterLazyGenerics.java @@ -6,32 +6,32 @@ class GetterLazyGenerics { } @java.lang.SuppressWarnings({"all", "unchecked"}) public E getField() { - java.lang.Object value = this.field.get(); - if (value == null) { + java.lang.Object $value = this.field.get(); + if ($value == null) { synchronized (this.field) { - value = this.field.get(); - if (value == null) { + $value = this.field.get(); + if ($value == null) { final E actualValue = getAny(); - value = actualValue == null ? this.field : actualValue; - this.field.set(value); + $value = actualValue == null ? this.field : actualValue; + this.field.set($value); } } } - return (E) (value == this.field ? null : value); + return (E) ($value == this.field ? null : $value); } @java.lang.SuppressWarnings({"all", "unchecked"}) public long getField2() { - java.lang.Object value = this.field2.get(); - if (value == null) { + java.lang.Object $value = this.field2.get(); + if ($value == null) { synchronized (this.field2) { - value = this.field2.get(); - if (value == null) { + $value = this.field2.get(); + if ($value == null) { final long actualValue = System.currentTimeMillis(); - value = actualValue; - this.field2.set(value); + $value = actualValue; + this.field2.set($value); } } } - return (java.lang.Long) value; + return (java.lang.Long) $value; } } \ No newline at end of file diff --git a/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java b/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java index 4476e463..199437a1 100644 --- a/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java +++ b/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java @@ -6,18 +6,18 @@ public class GetterLazyInAnonymousClass { @java.lang.SuppressWarnings({"all", "unchecked"}) public String getString() { - java.lang.Object value = this.string.get(); - if (value == null) { + java.lang.Object $value = this.string.get(); + if ($value == null) { synchronized (this.string) { - value = this.string.get(); - if (value == null) { + $value = this.string.get(); + if ($value == null) { final String actualValue = "test"; - value = actualValue == null ? this.string : actualValue; - this.string.set(value); + $value = actualValue == null ? this.string : actualValue; + this.string.set($value); } } } - return (String) (value == this.string ? null : value); + return (String) ($value == this.string ? null : $value); } } }; diff --git a/test/transform/resource/after-delombok/GetterLazyNative.java b/test/transform/resource/after-delombok/GetterLazyNative.java index f43d5490..a71a0354 100644 --- a/test/transform/resource/after-delombok/GetterLazyNative.java +++ b/test/transform/resource/after-delombok/GetterLazyNative.java @@ -10,137 +10,137 @@ class GetterLazyNative { private final java.util.concurrent.atomic.AtomicReference intArrayField = new java.util.concurrent.atomic.AtomicReference(); @java.lang.SuppressWarnings({"all", "unchecked"}) public boolean isBooleanField() { - java.lang.Object value = this.booleanField.get(); - if (value == null) { + java.lang.Object $value = this.booleanField.get(); + if ($value == null) { synchronized (this.booleanField) { - value = this.booleanField.get(); - if (value == null) { + $value = this.booleanField.get(); + if ($value == null) { final boolean actualValue = true; - value = actualValue; - this.booleanField.set(value); + $value = actualValue; + this.booleanField.set($value); } } } - return (java.lang.Boolean) value; + return (java.lang.Boolean) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public byte getByteField() { - java.lang.Object value = this.byteField.get(); - if (value == null) { + java.lang.Object $value = this.byteField.get(); + if ($value == null) { synchronized (this.byteField) { - value = this.byteField.get(); - if (value == null) { + $value = this.byteField.get(); + if ($value == null) { final byte actualValue = 1; - value = actualValue; - this.byteField.set(value); + $value = actualValue; + this.byteField.set($value); } } } - return (java.lang.Byte) value; + return (java.lang.Byte) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public short getShortField() { - java.lang.Object value = this.shortField.get(); - if (value == null) { + java.lang.Object $value = this.shortField.get(); + if ($value == null) { synchronized (this.shortField) { - value = this.shortField.get(); - if (value == null) { + $value = this.shortField.get(); + if ($value == null) { final short actualValue = 1; - value = actualValue; - this.shortField.set(value); + $value = actualValue; + this.shortField.set($value); } } } - return (java.lang.Short) value; + return (java.lang.Short) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public int getIntField() { - java.lang.Object value = this.intField.get(); - if (value == null) { + java.lang.Object $value = this.intField.get(); + if ($value == null) { synchronized (this.intField) { - value = this.intField.get(); - if (value == null) { + $value = this.intField.get(); + if ($value == null) { final int actualValue = 1; - value = actualValue; - this.intField.set(value); + $value = actualValue; + this.intField.set($value); } } } - return (java.lang.Integer) value; + return (java.lang.Integer) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public long getLongField() { - java.lang.Object value = this.longField.get(); - if (value == null) { + java.lang.Object $value = this.longField.get(); + if ($value == null) { synchronized (this.longField) { - value = this.longField.get(); - if (value == null) { + $value = this.longField.get(); + if ($value == null) { final long actualValue = 1; - value = actualValue; - this.longField.set(value); + $value = actualValue; + this.longField.set($value); } } } - return (java.lang.Long) value; + return (java.lang.Long) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public float getFloatField() { - java.lang.Object value = this.floatField.get(); - if (value == null) { + java.lang.Object $value = this.floatField.get(); + if ($value == null) { synchronized (this.floatField) { - value = this.floatField.get(); - if (value == null) { + $value = this.floatField.get(); + if ($value == null) { final float actualValue = 1.0F; - value = actualValue; - this.floatField.set(value); + $value = actualValue; + this.floatField.set($value); } } } - return (java.lang.Float) value; + return (java.lang.Float) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public double getDoubleField() { - java.lang.Object value = this.doubleField.get(); - if (value == null) { + java.lang.Object $value = this.doubleField.get(); + if ($value == null) { synchronized (this.doubleField) { - value = this.doubleField.get(); - if (value == null) { + $value = this.doubleField.get(); + if ($value == null) { final double actualValue = 1.0; - value = actualValue; - this.doubleField.set(value); + $value = actualValue; + this.doubleField.set($value); } } } - return (java.lang.Double) value; + return (java.lang.Double) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public char getCharField() { - java.lang.Object value = this.charField.get(); - if (value == null) { + java.lang.Object $value = this.charField.get(); + if ($value == null) { synchronized (this.charField) { - value = this.charField.get(); - if (value == null) { + $value = this.charField.get(); + if ($value == null) { final char actualValue = '1'; - value = actualValue; - this.charField.set(value); + $value = actualValue; + this.charField.set($value); } } } - return (java.lang.Character) value; + return (java.lang.Character) $value; } @java.lang.SuppressWarnings({"all", "unchecked"}) public int[] getIntArrayField() { - java.lang.Object value = this.intArrayField.get(); - if (value == null) { + java.lang.Object $value = this.intArrayField.get(); + if ($value == null) { synchronized (this.intArrayField) { - value = this.intArrayField.get(); - if (value == null) { + $value = this.intArrayField.get(); + if ($value == null) { final int[] actualValue = new int[] {1}; - value = actualValue == null ? this.intArrayField : actualValue; - this.intArrayField.set(value); + $value = actualValue == null ? this.intArrayField : actualValue; + this.intArrayField.set($value); } } } - return (int[]) (value == this.intArrayField ? null : value); + return (int[]) ($value == this.intArrayField ? null : $value); } } diff --git a/test/transform/resource/after-delombok/GetterLazyTransient.java b/test/transform/resource/after-delombok/GetterLazyTransient.java index 0fd85621..3d1a2be3 100644 --- a/test/transform/resource/after-delombok/GetterLazyTransient.java +++ b/test/transform/resource/after-delombok/GetterLazyTransient.java @@ -4,18 +4,18 @@ class GetterLazyTransient { private final transient int nonLazyTransientField = 3; @java.lang.SuppressWarnings({"all", "unchecked"}) public int getNonTransientField() { - java.lang.Object value = this.nonTransientField.get(); - if (value == null) { + java.lang.Object $value = this.nonTransientField.get(); + if ($value == null) { synchronized (this.nonTransientField) { - value = this.nonTransientField.get(); - if (value == null) { + $value = this.nonTransientField.get(); + if ($value == null) { final int actualValue = 1; - value = actualValue; - this.nonTransientField.set(value); + $value = actualValue; + this.nonTransientField.set($value); } } } - return (java.lang.Integer) value; + return (java.lang.Integer) $value; } @java.lang.SuppressWarnings("all") public int getNonLazyTransientField() { diff --git a/test/transform/resource/after-delombok/LockedInInitializer.java b/test/transform/resource/after-delombok/LockedInInitializer.java new file mode 100644 index 00000000..a4b687fc --- /dev/null +++ b/test/transform/resource/after-delombok/LockedInInitializer.java @@ -0,0 +1,41 @@ +public class LockedInInitializer { + public static final Runnable LOCKED = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.util.concurrent.locks.Lock $lock = new java.util.concurrent.locks.ReentrantLock(); + @Override + public void run() { + this.$lock.lock(); + try { + System.out.println("test"); + } finally { + this.$lock.unlock(); + } + } + }; + public static final Runnable LOCKED_READ = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + @Override + public void run() { + this.$lock.readLock().lock(); + try { + System.out.println("test"); + } finally { + this.$lock.readLock().unlock(); + } + } + }; + public static final Runnable LOCKED_WRITE = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + @Override + public void run() { + this.$lock.writeLock().lock(); + try { + System.out.println("test"); + } finally { + this.$lock.writeLock().unlock(); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/SkipSuppressWarnings.java b/test/transform/resource/after-delombok/SkipSuppressWarnings.java index 151d4e17..77bfdcc4 100644 --- a/test/transform/resource/after-delombok/SkipSuppressWarnings.java +++ b/test/transform/resource/after-delombok/SkipSuppressWarnings.java @@ -8,17 +8,17 @@ class SkipSuppressWarnings { @java.lang.SuppressWarnings({"unchecked"}) public String getField2() { - java.lang.Object value = this.field2.get(); - if (value == null) { + java.lang.Object $value = this.field2.get(); + if ($value == null) { synchronized (this.field2) { - value = this.field2.get(); - if (value == null) { + $value = this.field2.get(); + if ($value == null) { final String actualValue = ""; - value = actualValue == null ? this.field2 : actualValue; - this.field2.set(value); + $value = actualValue == null ? this.field2 : actualValue; + this.field2.set($value); } } } - return (String) (value == this.field2 ? null : value); + return (String) ($value == this.field2 ? null : $value); } } \ No newline at end of file diff --git a/test/transform/resource/after-delombok/SneakyThrowsInInitializer.java b/test/transform/resource/after-delombok/SneakyThrowsInInitializer.java new file mode 100644 index 00000000..b47dadc4 --- /dev/null +++ b/test/transform/resource/after-delombok/SneakyThrowsInInitializer.java @@ -0,0 +1,12 @@ +public class SneakyThrowsInInitializer { + public static final Runnable R = new Runnable() { + @Override + public void run() { + try { + System.out.println("test"); + } catch (final java.lang.Throwable $ex) { + throw lombok.Lombok.sneakyThrow($ex); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/SuperBuilderWithAnnotatedTypeParam.java b/test/transform/resource/after-delombok/SuperBuilderWithAnnotatedTypeParam.java new file mode 100644 index 00000000..f7ffe2fd --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithAnnotatedTypeParam.java @@ -0,0 +1,118 @@ +//version 8: +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +public class SuperBuilderWithAnnotatedTypeParam { + @Documented + @Target({ElementType.TYPE_USE, ElementType.ANNOTATION_TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MyAnnotation { + } + public static class Parent { + A field1; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder(field1=" + this.field1 + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder, SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public SuperBuilderWithAnnotatedTypeParam.Parent build() { + return new SuperBuilderWithAnnotatedTypeParam.Parent(this); + } + } + @java.lang.SuppressWarnings("all") + protected Parent(final SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder b) { + this.field1 = b.field1; + } + @java.lang.SuppressWarnings("all") + public static SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder builder() { + return new SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilderImpl(); + } + } + public static class Child extends Parent<@MyAnnotation String> { + double field3; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder> extends Parent.ParentBuilder<@MyAnnotation String, C, B> { + @java.lang.SuppressWarnings("all") + private double field3; + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public SuperBuilderWithAnnotatedTypeParam.Child build() { + return new SuperBuilderWithAnnotatedTypeParam.Child(this); + } + } + @java.lang.SuppressWarnings("all") + protected Child(final SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + @java.lang.SuppressWarnings("all") + public static SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder builder() { + return new SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilderImpl(); + } + } + public static void test() { + Child x = Child.builder().field3(0.0).field1("string").build(); + } +} diff --git a/test/transform/resource/after-delombok/SynchronizedInInitializer.java b/test/transform/resource/after-delombok/SynchronizedInInitializer.java new file mode 100644 index 00000000..c63f4e74 --- /dev/null +++ b/test/transform/resource/after-delombok/SynchronizedInInitializer.java @@ -0,0 +1,12 @@ +public class SynchronizedInInitializer { + public static final Runnable SYNCHRONIZED = new Runnable() { + @java.lang.SuppressWarnings("all") + private final java.lang.Object $lock = new java.lang.Object[0]; + @Override + public void run() { + synchronized (this.$lock) { + System.out.println("test"); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/WithOnNestedRecord.java b/test/transform/resource/after-delombok/WithOnNestedRecord.java new file mode 100644 index 00000000..89a75478 --- /dev/null +++ b/test/transform/resource/after-delombok/WithOnNestedRecord.java @@ -0,0 +1,21 @@ +// version 14: +public record WithOnNestedRecord() { + + public record Nested(String a, String b) { + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public WithOnNestedRecord.Nested withA(final String a) { + return this.a == a ? this : new WithOnNestedRecord.Nested(a, this.b); + } + + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public WithOnNestedRecord.Nested withB(final String b) { + return this.b == b ? this : new WithOnNestedRecord.Nested(this.a, b); + } + } +} diff --git a/test/transform/resource/after-ecj/BuilderOnNestedClass.java b/test/transform/resource/after-ecj/BuilderOnNestedClass.java new file mode 100644 index 00000000..b100223b --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderOnNestedClass.java @@ -0,0 +1,35 @@ +public class BuilderOnNestedClass { + public static @lombok.Builder class Nested { + public static @java.lang.SuppressWarnings("all") class NestedBuilder { + private @java.lang.SuppressWarnings("all") String a; + @java.lang.SuppressWarnings("all") NestedBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") BuilderOnNestedClass.Nested.NestedBuilder a(final String a) { + this.a = a; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderOnNestedClass.Nested build() { + return new BuilderOnNestedClass.Nested(this.a); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("BuilderOnNestedClass.Nested.NestedBuilder(a=" + this.a) + ")"); + } + } + private String a; + @java.lang.SuppressWarnings("all") Nested(final String a) { + super(); + this.a = a; + } + public static @java.lang.SuppressWarnings("all") BuilderOnNestedClass.Nested.NestedBuilder builder() { + return new BuilderOnNestedClass.Nested.NestedBuilder(); + } + } + private T t; + public BuilderOnNestedClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/BuilderOnNestedRecord.java b/test/transform/resource/after-ecj/BuilderOnNestedRecord.java new file mode 100644 index 00000000..4e025485 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderOnNestedRecord.java @@ -0,0 +1,30 @@ +public record BuilderOnNestedRecord(T t) { + public @lombok.Builder record Nested(String a) { + public static @java.lang.SuppressWarnings("all") class NestedBuilder { + private @java.lang.SuppressWarnings("all") String a; + @java.lang.SuppressWarnings("all") NestedBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") BuilderOnNestedRecord.Nested.NestedBuilder a(final String a) { + this.a = a; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderOnNestedRecord.Nested build() { + return new BuilderOnNestedRecord.Nested(this.a); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("BuilderOnNestedRecord.Nested.NestedBuilder(a=" + this.a) + ")"); + } + } +/* Implicit */ private final String a; + + public static @java.lang.SuppressWarnings("all") BuilderOnNestedRecord.Nested.NestedBuilder builder() { + return new BuilderOnNestedRecord.Nested.NestedBuilder(); + } + } +/* Implicit */ private final T t; + +} diff --git a/test/transform/resource/after-ecj/DelegateOnGetter.java b/test/transform/resource/after-ecj/DelegateOnGetter.java index f2b9a6cd..c23ea917 100644 --- a/test/transform/resource/after-ecj/DelegateOnGetter.java +++ b/test/transform/resource/after-ecj/DelegateOnGetter.java @@ -10,13 +10,13 @@ class DelegateOnGetter { super(); } public @Delegate @java.lang.SuppressWarnings({"all", "unchecked"}) Bar getBar() { - java.lang.Object value = this.bar.get(); - if ((value == null)) + java.lang.Object $value = this.bar.get(); + if (($value == null)) { synchronized (this.bar) { - value = this.bar.get(); - if ((value == null)) + $value = this.bar.get(); + if (($value == null)) { final Bar actualValue = new Bar() { x() { @@ -28,12 +28,12 @@ class DelegateOnGetter { return 42; } }; - value = ((actualValue == null) ? this.bar : actualValue); - this.bar.set(value); + $value = ((actualValue == null) ? this.bar : actualValue); + this.bar.set($value); } } } - return (Bar) ((value == this.bar) ? null : value); + return (Bar) (($value == this.bar) ? null : $value); } public @java.lang.SuppressWarnings("all") int getInt() { return this.getBar().getInt(); diff --git a/test/transform/resource/after-ecj/ExtensionMethodAmbiguousFunctional.java b/test/transform/resource/after-ecj/ExtensionMethodAmbiguousFunctional.java new file mode 100644 index 00000000..80d216b2 --- /dev/null +++ b/test/transform/resource/after-ecj/ExtensionMethodAmbiguousFunctional.java @@ -0,0 +1,20 @@ +import java.util.function.Consumer; +import java.util.function.Function; +import lombok.experimental.ExtensionMethod; +@ExtensionMethod({ExtensionMethodAmbiguousFunctional.Extensions.class}) class ExtensionMethodAmbiguousFunctional { + static class Extensions { + Extensions() { + super(); + } + public static void ambiguous(T t, Function function) { + } + public static void ambiguous(T t, Consumer function) { + } + } + ExtensionMethodAmbiguousFunctional() { + super(); + } + public void test() { + "".ambiguous(System.out::println); + } +} diff --git a/test/transform/resource/after-ecj/GetterLazy.java b/test/transform/resource/after-ecj/GetterLazy.java index b4567f04..7627ab16 100644 --- a/test/transform/resource/after-ecj/GetterLazy.java +++ b/test/transform/resource/after-ecj/GetterLazy.java @@ -9,20 +9,20 @@ class GetterLazy { super(); } public @java.lang.SuppressWarnings({"all", "unchecked"}) ValueType getFieldName() { - java.lang.Object value = this.fieldName.get(); - if ((value == null)) + java.lang.Object $value = this.fieldName.get(); + if (($value == null)) { synchronized (this.fieldName) { - value = this.fieldName.get(); - if ((value == null)) + $value = this.fieldName.get(); + if (($value == null)) { final ValueType actualValue = new ValueType(); - value = ((actualValue == null) ? this.fieldName : actualValue); - this.fieldName.set(value); + $value = ((actualValue == null) ? this.fieldName : actualValue); + this.fieldName.set($value); } } } - return (ValueType) ((value == this.fieldName) ? null : value); + return (ValueType) (($value == this.fieldName) ? null : $value); } } diff --git a/test/transform/resource/after-ecj/GetterLazyArguments.java b/test/transform/resource/after-ecj/GetterLazyArguments.java index 14086d81..bb51c4fc 100644 --- a/test/transform/resource/after-ecj/GetterLazyArguments.java +++ b/test/transform/resource/after-ecj/GetterLazyArguments.java @@ -18,107 +18,107 @@ class GetterLazyArguments { return null; } public @java.lang.SuppressWarnings({"all", "unchecked"}) String getField1() { - java.lang.Object value = this.field1.get(); - if ((value == null)) + java.lang.Object $value = this.field1.get(); + if (($value == null)) { synchronized (this.field1) { - value = this.field1.get(); - if ((value == null)) + $value = this.field1.get(); + if (($value == null)) { final String actualValue = stringInt("a", 1); - value = ((actualValue == null) ? this.field1 : actualValue); - this.field1.set(value); + $value = ((actualValue == null) ? this.field1 : actualValue); + this.field1.set($value); } } } - return (String) ((value == this.field1) ? null : 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)) + java.lang.Object $value = this.field2.get(); + if (($value == null)) { synchronized (this.field2) { - value = this.field2.get(); - if ((value == null)) + $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); + $value = ((actualValue == null) ? this.field2 : actualValue); + this.field2.set($value); } } } - return (String) ((value == this.field2) ? null : 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)) + java.lang.Object $value = this.field3.get(); + if (($value == null)) { synchronized (this.field3) { - value = this.field3.get(); - if ((value == null)) + $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); + $value = ((actualValue == null) ? this.field3 : actualValue); + this.field3.set($value); } } } - return (String) ((value == this.field3) ? null : 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)) + java.lang.Object $value = this.field4.get(); + if (($value == null)) { synchronized (this.field4) { - value = this.field4.get(); - if ((value == null)) + $value = this.field4.get(); + if (($value == null)) { final String actualValue = stringRunnable(fun(), () -> { }); - value = ((actualValue == null) ? this.field4 : actualValue); - this.field4.set(value); + $value = ((actualValue == null) ? this.field4 : actualValue); + this.field4.set($value); } } } - return (String) ((value == this.field4) ? null : 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)) + java.lang.Object $value = this.field5.get(); + if (($value == null)) { synchronized (this.field5) { - value = this.field5.get(); - if ((value == null)) + $value = this.field5.get(); + if (($value == null)) { final String actualValue = stringRunnable("a", () -> { }); - value = ((actualValue == null) ? this.field5 : actualValue); - this.field5.set(value); + $value = ((actualValue == null) ? this.field5 : actualValue); + this.field5.set($value); } } } - return (String) ((value == this.field5) ? null : value); + return (String) (($value == this.field5) ? null : $value); } public @java.lang.SuppressWarnings({"all", "unchecked"}) String getField6() { - java.lang.Object value = this.field6.get(); - if ((value == null)) + java.lang.Object $value = this.field6.get(); + if (($value == null)) { synchronized (this.field6) { - value = this.field6.get(); - if ((value == null)) + $value = this.field6.get(); + if (($value == null)) { final String actualValue = (true ? stringInt((true ? "a" : "b"), (true ? 1 : 0)) : ""); - value = ((actualValue == null) ? this.field6 : actualValue); - this.field6.set(value); + $value = ((actualValue == null) ? this.field6 : actualValue); + this.field6.set($value); } } } - return (String) ((value == this.field6) ? null : value); + return (String) (($value == this.field6) ? null : $value); } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/GetterLazyBoolean.java b/test/transform/resource/after-ecj/GetterLazyBoolean.java index ad319755..40ecb856 100644 --- a/test/transform/resource/after-ecj/GetterLazyBoolean.java +++ b/test/transform/resource/after-ecj/GetterLazyBoolean.java @@ -8,38 +8,38 @@ return true; } public @java.lang.SuppressWarnings({"all", "unchecked"}) boolean isBooleanValue() { - java.lang.Object value = this.booleanValue.get(); - if ((value == null)) + java.lang.Object $value = this.booleanValue.get(); + if (($value == null)) { synchronized (this.booleanValue) { - value = this.booleanValue.get(); - if ((value == null)) + $value = this.booleanValue.get(); + if (($value == null)) { final boolean actualValue = calculateBoolean(); - value = actualValue; - this.booleanValue.set(value); + $value = actualValue; + this.booleanValue.set($value); } } } - return (java.lang.Boolean) value; + return (java.lang.Boolean) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) boolean isOtherBooleanValue() { - java.lang.Object value = this.otherBooleanValue.get(); - if ((value == null)) + java.lang.Object $value = this.otherBooleanValue.get(); + if (($value == null)) { synchronized (this.otherBooleanValue) { - value = this.otherBooleanValue.get(); - if ((value == null)) + $value = this.otherBooleanValue.get(); + if (($value == null)) { final boolean actualValue = (! calculateBoolean()); - value = actualValue; - this.otherBooleanValue.set(value); + $value = actualValue; + this.otherBooleanValue.set($value); } } } - return (java.lang.Boolean) value; + return (java.lang.Boolean) $value; } public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) diff --git a/test/transform/resource/after-ecj/GetterLazyEahcToString.java b/test/transform/resource/after-ecj/GetterLazyEahcToString.java index 5197f4e1..f4f4ed37 100644 --- a/test/transform/resource/after-ecj/GetterLazyEahcToString.java +++ b/test/transform/resource/after-ecj/GetterLazyEahcToString.java @@ -5,21 +5,21 @@ super(); } public @java.lang.SuppressWarnings({"all", "unchecked"}) String getValue() { - java.lang.Object value = this.value.get(); - if ((value == null)) + java.lang.Object $value = this.value.get(); + if (($value == null)) { synchronized (this.value) { - value = this.value.get(); - if ((value == null)) + $value = this.value.get(); + if (($value == null)) { final String actualValue = ""; - value = ((actualValue == null) ? this.value : actualValue); - this.value.set(value); + $value = ((actualValue == null) ? this.value : actualValue); + this.value.set($value); } } } - return (String) ((value == this.value) ? null : value); + return (String) (($value == this.value) ? null : $value); } public @java.lang.SuppressWarnings("all") String getValue2() { return this.value2; diff --git a/test/transform/resource/after-ecj/GetterLazyGenerics.java b/test/transform/resource/after-ecj/GetterLazyGenerics.java index 67ef5543..3a2a06c1 100644 --- a/test/transform/resource/after-ecj/GetterLazyGenerics.java +++ b/test/transform/resource/after-ecj/GetterLazyGenerics.java @@ -8,37 +8,37 @@ class GetterLazyGenerics { return null; } public @java.lang.SuppressWarnings({"all", "unchecked"}) E getField() { - java.lang.Object value = this.field.get(); - if ((value == null)) + java.lang.Object $value = this.field.get(); + if (($value == null)) { synchronized (this.field) { - value = this.field.get(); - if ((value == null)) + $value = this.field.get(); + if (($value == null)) { final E actualValue = getAny(); - value = ((actualValue == null) ? this.field : actualValue); - this.field.set(value); + $value = ((actualValue == null) ? this.field : actualValue); + this.field.set($value); } } } - return (E) ((value == this.field) ? null : value); + return (E) (($value == this.field) ? null : $value); } public @java.lang.SuppressWarnings({"all", "unchecked"}) long getField2() { - java.lang.Object value = this.field2.get(); - if ((value == null)) + java.lang.Object $value = this.field2.get(); + if (($value == null)) { synchronized (this.field2) { - value = this.field2.get(); - if ((value == null)) + $value = this.field2.get(); + if (($value == null)) { final long actualValue = System.currentTimeMillis(); - value = actualValue; - this.field2.set(value); + $value = actualValue; + this.field2.set($value); } } } - return (java.lang.Long) value; + return (java.lang.Long) $value; } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java b/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java index ab8bc599..dadd8e71 100644 --- a/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java +++ b/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java @@ -7,21 +7,21 @@ public class GetterLazyInAnonymousClass { super(); } public @java.lang.SuppressWarnings({"all", "unchecked"}) String getString() { - java.lang.Object value = this.string.get(); - if ((value == null)) + java.lang.Object $value = this.string.get(); + if (($value == null)) { synchronized (this.string) { - value = this.string.get(); - if ((value == null)) + $value = this.string.get(); + if (($value == null)) { final String actualValue = "test"; - value = ((actualValue == null) ? this.string : actualValue); - this.string.set(value); + $value = ((actualValue == null) ? this.string : actualValue); + this.string.set($value); } } } - return (String) ((value == this.string) ? null : value); + return (String) (($value == this.string) ? null : $value); } } x() { diff --git a/test/transform/resource/after-ecj/GetterLazyNative.java b/test/transform/resource/after-ecj/GetterLazyNative.java index 7808068e..c2769c51 100644 --- a/test/transform/resource/after-ecj/GetterLazyNative.java +++ b/test/transform/resource/after-ecj/GetterLazyNative.java @@ -12,156 +12,156 @@ class GetterLazyNative { super(); } public @java.lang.SuppressWarnings({"all", "unchecked"}) boolean isBooleanField() { - java.lang.Object value = this.booleanField.get(); - if ((value == null)) + java.lang.Object $value = this.booleanField.get(); + if (($value == null)) { synchronized (this.booleanField) { - value = this.booleanField.get(); - if ((value == null)) + $value = this.booleanField.get(); + if (($value == null)) { final boolean actualValue = true; - value = actualValue; - this.booleanField.set(value); + $value = actualValue; + this.booleanField.set($value); } } } - return (java.lang.Boolean) value; + return (java.lang.Boolean) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) byte getByteField() { - java.lang.Object value = this.byteField.get(); - if ((value == null)) + java.lang.Object $value = this.byteField.get(); + if (($value == null)) { synchronized (this.byteField) { - value = this.byteField.get(); - if ((value == null)) + $value = this.byteField.get(); + if (($value == null)) { final byte actualValue = 1; - value = actualValue; - this.byteField.set(value); + $value = actualValue; + this.byteField.set($value); } } } - return (java.lang.Byte) value; + return (java.lang.Byte) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) short getShortField() { - java.lang.Object value = this.shortField.get(); - if ((value == null)) + java.lang.Object $value = this.shortField.get(); + if (($value == null)) { synchronized (this.shortField) { - value = this.shortField.get(); - if ((value == null)) + $value = this.shortField.get(); + if (($value == null)) { final short actualValue = 1; - value = actualValue; - this.shortField.set(value); + $value = actualValue; + this.shortField.set($value); } } } - return (java.lang.Short) value; + return (java.lang.Short) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) int getIntField() { - java.lang.Object value = this.intField.get(); - if ((value == null)) + java.lang.Object $value = this.intField.get(); + if (($value == null)) { synchronized (this.intField) { - value = this.intField.get(); - if ((value == null)) + $value = this.intField.get(); + if (($value == null)) { final int actualValue = 1; - value = actualValue; - this.intField.set(value); + $value = actualValue; + this.intField.set($value); } } } - return (java.lang.Integer) value; + return (java.lang.Integer) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) long getLongField() { - java.lang.Object value = this.longField.get(); - if ((value == null)) + java.lang.Object $value = this.longField.get(); + if (($value == null)) { synchronized (this.longField) { - value = this.longField.get(); - if ((value == null)) + $value = this.longField.get(); + if (($value == null)) { final long actualValue = 1; - value = actualValue; - this.longField.set(value); + $value = actualValue; + this.longField.set($value); } } } - return (java.lang.Long) value; + return (java.lang.Long) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) float getFloatField() { - java.lang.Object value = this.floatField.get(); - if ((value == null)) + java.lang.Object $value = this.floatField.get(); + if (($value == null)) { synchronized (this.floatField) { - value = this.floatField.get(); - if ((value == null)) + $value = this.floatField.get(); + if (($value == null)) { final float actualValue = 1.0f; - value = actualValue; - this.floatField.set(value); + $value = actualValue; + this.floatField.set($value); } } } - return (java.lang.Float) value; + return (java.lang.Float) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) double getDoubleField() { - java.lang.Object value = this.doubleField.get(); - if ((value == null)) + java.lang.Object $value = this.doubleField.get(); + if (($value == null)) { synchronized (this.doubleField) { - value = this.doubleField.get(); - if ((value == null)) + $value = this.doubleField.get(); + if (($value == null)) { final double actualValue = 1.0; - value = actualValue; - this.doubleField.set(value); + $value = actualValue; + this.doubleField.set($value); } } } - return (java.lang.Double) value; + return (java.lang.Double) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) char getCharField() { - java.lang.Object value = this.charField.get(); - if ((value == null)) + java.lang.Object $value = this.charField.get(); + if (($value == null)) { synchronized (this.charField) { - value = this.charField.get(); - if ((value == null)) + $value = this.charField.get(); + if (($value == null)) { final char actualValue = '1'; - value = actualValue; - this.charField.set(value); + $value = actualValue; + this.charField.set($value); } } } - return (java.lang.Character) value; + return (java.lang.Character) $value; } public @java.lang.SuppressWarnings({"all", "unchecked"}) int[] getIntArrayField() { - java.lang.Object value = this.intArrayField.get(); - if ((value == null)) + java.lang.Object $value = this.intArrayField.get(); + if (($value == null)) { synchronized (this.intArrayField) { - value = this.intArrayField.get(); - if ((value == null)) + $value = this.intArrayField.get(); + if (($value == null)) { final int[] actualValue = new int[]{1}; - value = ((actualValue == null) ? this.intArrayField : actualValue); - this.intArrayField.set(value); + $value = ((actualValue == null) ? this.intArrayField : actualValue); + this.intArrayField.set($value); } } } - return (int[]) ((value == this.intArrayField) ? null : value); + return (int[]) (($value == this.intArrayField) ? null : $value); } } diff --git a/test/transform/resource/after-ecj/GetterLazyTransient.java b/test/transform/resource/after-ecj/GetterLazyTransient.java index 7e5f4a41..b97fe533 100644 --- a/test/transform/resource/after-ecj/GetterLazyTransient.java +++ b/test/transform/resource/after-ecj/GetterLazyTransient.java @@ -6,21 +6,21 @@ class GetterLazyTransient { super(); } public @java.lang.SuppressWarnings({"all", "unchecked"}) int getNonTransientField() { - java.lang.Object value = this.nonTransientField.get(); - if ((value == null)) + java.lang.Object $value = this.nonTransientField.get(); + if (($value == null)) { synchronized (this.nonTransientField) { - value = this.nonTransientField.get(); - if ((value == null)) + $value = this.nonTransientField.get(); + if (($value == null)) { final int actualValue = 1; - value = actualValue; - this.nonTransientField.set(value); + $value = actualValue; + this.nonTransientField.set($value); } } } - return (java.lang.Integer) value; + return (java.lang.Integer) $value; } public @java.lang.SuppressWarnings("all") int getNonLazyTransientField() { return this.nonLazyTransientField; diff --git a/test/transform/resource/after-ecj/LockedInInitializer.java b/test/transform/resource/after-ecj/LockedInInitializer.java new file mode 100644 index 00000000..aea88d0d --- /dev/null +++ b/test/transform/resource/after-ecj/LockedInInitializer.java @@ -0,0 +1,49 @@ +import lombok.Locked; +public class LockedInInitializer { + public static final Runnable LOCKED = new Runnable() { + private final java.util.concurrent.locks.Lock $lock = new java.util.concurrent.locks.ReentrantLock(); + public @Override @Locked void run() { + this.$lock.lock(); + try + { + System.out.println("test"); + } + finally + { + this.$lock.unlock(); + } + } + }; + public static final Runnable LOCKED_READ = new Runnable() { + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + public @Override @Locked.Read void run() { + this.$lock.readLock().lock(); + try + { + System.out.println("test"); + } + finally + { + this.$lock.readLock().unlock(); + } + } + }; + public static final Runnable LOCKED_WRITE = new Runnable() { + private final java.util.concurrent.locks.ReadWriteLock $lock = new java.util.concurrent.locks.ReentrantReadWriteLock(); + public @Override @Locked.Write void run() { + this.$lock.writeLock().lock(); + try + { + System.out.println("test"); + } + finally + { + this.$lock.writeLock().unlock(); + } + } + }; + () { + } + public LockedInInitializer() { + } +} diff --git a/test/transform/resource/after-ecj/SkipSuppressWarnings.java b/test/transform/resource/after-ecj/SkipSuppressWarnings.java index 53032519..76b79fe2 100644 --- a/test/transform/resource/after-ecj/SkipSuppressWarnings.java +++ b/test/transform/resource/after-ecj/SkipSuppressWarnings.java @@ -8,20 +8,20 @@ class SkipSuppressWarnings { return this.field; } public @java.lang.SuppressWarnings({"unchecked"}) String getField2() { - java.lang.Object value = this.field2.get(); - if ((value == null)) + java.lang.Object $value = this.field2.get(); + if (($value == null)) { synchronized (this.field2) { - value = this.field2.get(); - if ((value == null)) + $value = this.field2.get(); + if (($value == null)) { final String actualValue = ""; - value = ((actualValue == null) ? this.field2 : actualValue); - this.field2.set(value); + $value = ((actualValue == null) ? this.field2 : actualValue); + this.field2.set($value); } } } - return (String) ((value == this.field2) ? null : value); + return (String) (($value == this.field2) ? null : $value); } } \ No newline at end of file diff --git a/test/transform/resource/after-ecj/SneakyThrowsInInitializer.java b/test/transform/resource/after-ecj/SneakyThrowsInInitializer.java new file mode 100644 index 00000000..2e981b02 --- /dev/null +++ b/test/transform/resource/after-ecj/SneakyThrowsInInitializer.java @@ -0,0 +1,19 @@ +import lombok.SneakyThrows; +public class SneakyThrowsInInitializer { + public static final Runnable R = new Runnable() { + public @Override @SneakyThrows void run() { + try + { + System.out.println("test"); + } + catch (final java.lang.Throwable $ex) + { + throw lombok.Lombok.sneakyThrow($ex); + } + } + }; + () { + } + public SneakyThrowsInInitializer() { + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithAnnotatedTypeParam.java b/test/transform/resource/after-ecj/SuperBuilderWithAnnotatedTypeParam.java new file mode 100644 index 00000000..9dea5ba0 --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithAnnotatedTypeParam.java @@ -0,0 +1,95 @@ +//version 8: +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +public class SuperBuilderWithAnnotatedTypeParam { + public @Documented @Target({ElementType.TYPE_USE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { + } + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder> { + private @java.lang.SuppressWarnings("all") A field1; + public ParentBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") B field1(final A field1) { + this.field1 = field1; + return self(); + } + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder(field1=" + this.field1) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder, SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilderImpl> { + private ParentBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") SuperBuilderWithAnnotatedTypeParam.Parent build() { + return new SuperBuilderWithAnnotatedTypeParam.Parent(this); + } + } + A field1; + protected @java.lang.SuppressWarnings("all") Parent(final SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder b) { + super(); + this.field1 = b.field1; + } + public static @java.lang.SuppressWarnings("all") SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilder builder() { + return new SuperBuilderWithAnnotatedTypeParam.Parent.ParentBuilderImpl(); + } + } + public static @lombok.experimental.SuperBuilder class Child extends Parent<@MyAnnotation String> { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder<@MyAnnotation String, C, B> { + private @java.lang.SuppressWarnings("all") double field3; + public ChildBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") B field3(final double field3) { + this.field3 = field3; + return self(); + } + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder { + private ChildBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") SuperBuilderWithAnnotatedTypeParam.Child build() { + return new SuperBuilderWithAnnotatedTypeParam.Child(this); + } + } + double field3; + protected @java.lang.SuppressWarnings("all") Child(final SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static @java.lang.SuppressWarnings("all") SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilder builder() { + return new SuperBuilderWithAnnotatedTypeParam.Child.ChildBuilderImpl(); + } + } + public SuperBuilderWithAnnotatedTypeParam() { + super(); + } + public static void test() { + Child x = Child.builder().field3(0.0).field1("string").build(); + } +} diff --git a/test/transform/resource/after-ecj/SynchronizedInInitializer.java b/test/transform/resource/after-ecj/SynchronizedInInitializer.java new file mode 100644 index 00000000..dad6ff8d --- /dev/null +++ b/test/transform/resource/after-ecj/SynchronizedInInitializer.java @@ -0,0 +1,16 @@ +import lombok.Synchronized; +public class SynchronizedInInitializer { + public static final Runnable SYNCHRONIZED = new Runnable() { + private final java.lang.Object $lock = new java.lang.Object[0]; + public @Override @Synchronized void run() { + synchronized (this.$lock) + { + System.out.println("test"); + } + } + }; + () { + } + public SynchronizedInInitializer() { + } +} diff --git a/test/transform/resource/after-ecj/WithOnNestedRecord.java b/test/transform/resource/after-ecj/WithOnNestedRecord.java new file mode 100644 index 00000000..a83ac94c --- /dev/null +++ b/test/transform/resource/after-ecj/WithOnNestedRecord.java @@ -0,0 +1,20 @@ +import lombok.With; +public record WithOnNestedRecord() { + public @With record Nested(String a, String b) { +/* Implicit */ private final String a; +/* Implicit */ private final String b; + + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") WithOnNestedRecord.Nested withA(final String a) { + return ((this.a == a) ? this : new WithOnNestedRecord.Nested(a, this.b)); + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") WithOnNestedRecord.Nested withB(final String b) { + return ((this.b == b) ? this : new WithOnNestedRecord.Nested(this.a, b)); + } + } +} diff --git a/test/transform/resource/before/BuilderOnNestedClass.java b/test/transform/resource/before/BuilderOnNestedClass.java new file mode 100644 index 00000000..741ac520 --- /dev/null +++ b/test/transform/resource/before/BuilderOnNestedClass.java @@ -0,0 +1,8 @@ +public class BuilderOnNestedClass { + private T t; + + @lombok.Builder + public static class Nested { + private String a; + } +} diff --git a/test/transform/resource/before/BuilderOnNestedRecord.java b/test/transform/resource/before/BuilderOnNestedRecord.java new file mode 100644 index 00000000..18a99962 --- /dev/null +++ b/test/transform/resource/before/BuilderOnNestedRecord.java @@ -0,0 +1,7 @@ +// version 14: +public record BuilderOnNestedRecord(T t) { + @lombok.Builder + public record Nested(String a) { + + } +} diff --git a/test/transform/resource/before/ExtensionMethodAmbiguousFunctional.java b/test/transform/resource/before/ExtensionMethodAmbiguousFunctional.java new file mode 100644 index 00000000..65c08404 --- /dev/null +++ b/test/transform/resource/before/ExtensionMethodAmbiguousFunctional.java @@ -0,0 +1,20 @@ +//version 8: +import java.util.function.Consumer; +import java.util.function.Function; + +import lombok.experimental.ExtensionMethod; + +@ExtensionMethod({ExtensionMethodAmbiguousFunctional.Extensions.class}) +class ExtensionMethodAmbiguousFunctional { + public void test() { + "".ambiguous(System.out::println); + } + + static class Extensions { + public static void ambiguous(T t, Function function) { + } + + public static void ambiguous(T t, Consumer function) { + } + } +} diff --git a/test/transform/resource/before/LockedInInitializer.java b/test/transform/resource/before/LockedInInitializer.java new file mode 100644 index 00000000..f4df0247 --- /dev/null +++ b/test/transform/resource/before/LockedInInitializer.java @@ -0,0 +1,26 @@ +//eclipse: verify diet +import lombok.Locked; + +public class LockedInInitializer { + public static final Runnable LOCKED = new Runnable() { + @Override + @Locked + public void run() { + System.out.println("test"); + } + }; + public static final Runnable LOCKED_READ = new Runnable() { + @Override + @Locked.Read + public void run() { + System.out.println("test"); + } + }; + public static final Runnable LOCKED_WRITE = new Runnable() { + @Override + @Locked.Write + public void run() { + System.out.println("test"); + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/RecordNonNull b/test/transform/resource/before/RecordNonNull deleted file mode 100644 index e69de29b..00000000 diff --git a/test/transform/resource/before/SneakyThrowsInInitializer.java b/test/transform/resource/before/SneakyThrowsInInitializer.java new file mode 100644 index 00000000..87f77309 --- /dev/null +++ b/test/transform/resource/before/SneakyThrowsInInitializer.java @@ -0,0 +1,15 @@ +//eclipse: verify diet +import lombok.SneakyThrows; + +public class SneakyThrowsInInitializer { + + public static final Runnable R = new Runnable() { + + @Override + @SneakyThrows + public void run() { + System.out.println("test"); + + } + }; +} diff --git a/test/transform/resource/before/SuperBuilderWithAnnotatedTypeParam.java b/test/transform/resource/before/SuperBuilderWithAnnotatedTypeParam.java new file mode 100644 index 00000000..4f5bed50 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithAnnotatedTypeParam.java @@ -0,0 +1,29 @@ +//version 8: +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; + +public class SuperBuilderWithAnnotatedTypeParam { + @Documented + @Target( { ElementType.TYPE_USE, ElementType.ANNOTATION_TYPE }) + @Retention(RetentionPolicy.RUNTIME) + public @interface MyAnnotation { + } + + @lombok.experimental.SuperBuilder + public static class Parent { + A field1; + } + + @lombok.experimental.SuperBuilder + public static class Child extends Parent<@MyAnnotation String> { + double field3; + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1("string").build(); + } +} diff --git a/test/transform/resource/before/SynchronizedInInitializer.java b/test/transform/resource/before/SynchronizedInInitializer.java new file mode 100644 index 00000000..4d295d9e --- /dev/null +++ b/test/transform/resource/before/SynchronizedInInitializer.java @@ -0,0 +1,12 @@ +//eclipse: verify diet +import lombok.Synchronized; + +public class SynchronizedInInitializer { + public static final Runnable SYNCHRONIZED = new Runnable() { + @Override + @Synchronized + public void run() { + System.out.println("test"); + } + }; +} \ No newline at end of file diff --git a/test/transform/resource/before/WithOnNestedRecord.java b/test/transform/resource/before/WithOnNestedRecord.java new file mode 100644 index 00000000..d8d28f35 --- /dev/null +++ b/test/transform/resource/before/WithOnNestedRecord.java @@ -0,0 +1,9 @@ +// version 14: +import lombok.With; + +public record WithOnNestedRecord() { + @With + public record Nested(String a, String b) { + + } +} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/ExtensionMethodAmbiguousFunctional.java.messages b/test/transform/resource/messages-delombok/ExtensionMethodAmbiguousFunctional.java.messages new file mode 100644 index 00000000..9fa3414f --- /dev/null +++ b/test/transform/resource/messages-delombok/ExtensionMethodAmbiguousFunctional.java.messages @@ -0,0 +1 @@ +9 reference to ambiguous is ambiguous both method ambiguous(T,java.util.function.Function) in ExtensionMethodAmbiguousFunctional.Extensions and method ambiguous(T,java.util.function.Consumer) in ExtensionMethodAmbiguousFunctional.Extensions match diff --git a/test/transform/resource/messages-ecj/ExtensionMethodAmbiguousFunctional.java.messages b/test/transform/resource/messages-ecj/ExtensionMethodAmbiguousFunctional.java.messages new file mode 100644 index 00000000..63e76c93 --- /dev/null +++ b/test/transform/resource/messages-ecj/ExtensionMethodAmbiguousFunctional.java.messages @@ -0,0 +1 @@ +10 The method ambiguous(String, Function) is ambiguous for the type ExtensionMethodAmbiguousFunctional.Extensions diff --git a/website/templates/features/Builder.html b/website/templates/features/Builder.html index 1461161f..05881083 100644 --- a/website/templates/features/Builder.html +++ b/website/templates/features/Builder.html @@ -66,7 +66,7 @@

Now that the "method" mode is clear, putting a @Builder annotation on a constructor functions similarly; effectively, constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their type parameters are the same as the type parameters of the class itself.

- Finally, applying @Builder to a class is as if you added @AllArgsConstructor(access = AccessLevel.PACKAGE) to the class and applied the @Builder annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself. If you do have an explicit constructor, put the @Builder annotation on the constructor instead of on the class. Note that if you put both `@Value` and `@Builder` on a class, the package-private constructor that `@Builder` wants to generate 'wins' and suppresses the constructor that `@Value` wants to make. + Finally, applying @Builder to a class is as if you added @AllArgsConstructor(access = AccessLevel.PACKAGE) to the class and applied the @Builder annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself or allowed lombok to create one such as with @NoArgsConstructor. If you do have an explicit constructor, put the @Builder annotation on the constructor instead of on the class. Note that if you put both `@Value` and `@Builder` on a class, the package-private constructor that `@Builder` wants to generate 'wins' and suppresses the constructor that `@Value` wants to make.

If using @Builder to generate builders to produce instances of your own class (this is always the case unless adding @Builder to a method that doesn't return your own type), you can use @Builder(toBuilder = true) to also generate an instance method in your class called toBuilder(); it creates a new builder that starts out with all the values of this instance. You can put the @Builder.ObtainVia annotation on the parameters (in case of a constructor or method) or fields (in case of @Builder on a type) to indicate alternative means by which the value for that field/parameter is obtained from this instance. For example, you can specify a method to be invoked: @Builder.ObtainVia(method = "calculateFoo").

@@ -100,7 +100,8 @@

If a certain field/parameter is never set during a build session, then it always gets 0 / null / false. If you've put @Builder on a class (and not a method or constructor) you can instead specify the default directly on the field, and annotate the field with @Builder.Default:
- @Builder.Default private final long created = System.currentTimeMillis(); + @Builder.Default private final long created = System.currentTimeMillis();
+ Calling Lombok-generated constructors such as @NoArgsConstructor will also make use of the defaults specified using @Builder.Default however explicit constructors will no longer use the default values and will need to be set manually or call a Lombok-generated constructor such as this(); to set the defaults.

diff --git a/website/templates/features/GetterSetter.html b/website/templates/features/GetterSetter.html index 8b16d34d..8cf25ee4 100644 --- a/website/templates/features/GetterSetter.html +++ b/website/templates/features/GetterSetter.html @@ -28,7 +28,7 @@
lombok.accessors.fluent = [true | false] (default: false)
- If set to true, generated getters and setters will not be prefixed with the bean-standard 'get, is or set; instead, the methods will use the same name as the field (minus prefixes). An explicitly configured chain parameter of an @Accessors annotation takes precedence over this setting. + If set to true, generated getters and setters will not be prefixed with the bean-standard 'get, is or set; instead, the methods will use the same name as the field (minus prefixes). An explicitly configured fluent parameter of an @Accessors annotation takes precedence over this setting.
lombok.accessors.prefix += a field prefix (default: empty list)
diff --git a/website/templates/features/Locked.html b/website/templates/features/Locked.html index 105bf6dc..fa041975 100644 --- a/website/templates/features/Locked.html +++ b/website/templates/features/Locked.html @@ -1,4 +1,4 @@ -<#import "../_features.html" as f> +<#import "_features.html" as f> <@f.scaffold title="@Locked" logline="Pop it and lock it! ReentrantLock, now with less hassle."> <@f.history> diff --git a/website/usageExamples/experimental/LockedExample_post.jpage b/website/usageExamples/LockedExample_post.jpage similarity index 100% rename from website/usageExamples/experimental/LockedExample_post.jpage rename to website/usageExamples/LockedExample_post.jpage diff --git a/website/usageExamples/experimental/LockedExample_pre.jpage b/website/usageExamples/LockedExample_pre.jpage similarity index 100% rename from website/usageExamples/experimental/LockedExample_pre.jpage rename to website/usageExamples/LockedExample_pre.jpage