diff options
196 files changed, 2599 insertions, 268 deletions
@@ -49,6 +49,7 @@ Takuya Murakami <tmurakam@tmurakam.org> Thomas Darimont <thomas.darimont@gmail.com> Till Brychcy <till.brychcy@mercateo.com> Victor Williams Stafusa da Silva <victorwssilva@gmail.com> +Yonatan Sherwin <yonatansherwin@gmail.com> Yun Zhi Lin <yun@yunspace.com> By adding your name to this list, you grant full and irrevocable copyright and patent indemnity to Project Lombok and all use of Project Lombok in relation to all commits you add to Project Lombok, and you certify that you have the right to do so. diff --git a/buildScripts/tests.ant.xml b/buildScripts/tests.ant.xml index 9d9e9541..838ac353 100644 --- a/buildScripts/tests.ant.xml +++ b/buildScripts/tests.ant.xml @@ -152,13 +152,18 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn <macrodef name="test.eclipse-X"> <attribute name="version" /> + <attribute name="compiler.compliance.level" default="latest" /> <sequential> - <echo>Running TestEclipse on eclipse-@{version} on JVM${ant.java.version}.</echo> + <condition property="compiler.compliance.level" value="-Dcompiler.compliance.level=@{compiler.compliance.level}" else="-Dnot=set"> + <not><equals arg1="@{compiler.compliance.level}" arg2="latest" /></not> + </condition> + <echo>Running TestEclipse on eclipse-@{version} on JVM${ant.java.version} using. Compiler compliance level: @{compiler.compliance.level}</echo> <junit haltonfailure="yes" fork="true" forkmode="once"> <formatter classname="lombok.ant.SimpleTestFormatter" usefile="false" unless="tests.quiet" /> <jvmarg value="-Xbootclasspath/a:${jdk8-rt.loc}" /> <jvmarg value="-Ddelombok.bootclasspath=${jdk8-rt.loc}" /> <jvmarg value="-javaagent:dist/lombok.jar" /> + <jvmarg value="${compiler.compliance.level}" /> <classpath location="build/ant" /> <classpath refid="cp.test" /> <classpath refid="cp.stripe" /> @@ -175,11 +180,16 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn <test.eclipse-X version="oxygen" /> </target> - <target name="test.eclipse-202006" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, testing the 2020-03 release of eclipse"> + <target name="test.eclipse-202006" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, testing the 2020-06 release of eclipse"> <fetchdep.eclipse version="202006" /> <test.eclipse-X version="202006" /> </target> + <target name="test.eclipse-202006-jdk8" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, testing the 2020-06 release of eclipse with compiler compliance level 8"> + <fetchdep.eclipse version="202006" /> + <test.eclipse-X version="202006" compiler.compliance.level="8" /> + </target> + <macrodef name="test.ecj-X"> <attribute name="version" /> <sequential> @@ -217,5 +227,5 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn </target> <target name="test" depends="test.javacCurrent, test.eclipse-202006" description="runs the tests against the default JVM, javac, and eclipse" /> - <target name="test.broad" depends="test.javac8, test.javac14, test.eclipse-oxygen, test.eclipse-202006" description="runs the tests against the default JVM, javac, and eclipse" /> + <target name="test.broad" depends="test.javac8, test.javac14, test.eclipse-oxygen, test.eclipse-202006, test.eclipse-202006-jdk8" description="runs the tests against the default JVM, javac, and eclipse" /> </project> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 583736f1..5c13e2e2 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,8 +1,17 @@ Lombok Changelog ---------------- -### v1.18.21 "Edgy Guinea Pig" -* Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). +### v1.18.24 "Edgy Guinea Pig" +* FEATURE: Turning a field named `uShape` into a getter is tricky: `getUShape` or `getuShape`? The community is split on which style to use. Lombok does `getUShape`, but if you prefer the `getuShape` style, add to `lombok.config`: `lombok.accessors.capitalization = beanspec`. [Issue #2693](https://github.com/projectlombok/lombok/issues/2693) [Pull Request #2996](https://github.com/projectlombok/lombok/pull/2996). Thanks __@YonathanSherwin__! +* BUGFIX: Various save actions and refactor scripts in eclipse work better. [Issue #2995](https://github.com/projectlombok/lombok/issues/2995) [Issue #1309](https://github.com/projectlombok/lombok/issues/1309) [Issue #2985](https://github.com/projectlombok/lombok/issues/2985) [Issue #2509](https://github.com/projectlombok/lombok/issues/2509) + +### v1.18.22 (October 6th, 2021) +* PLATFORM: JDK17 support added. [Issue #2898](https://github.com/projectlombok/lombok/issues/2898). +* FEATURE: Added the `@StandardException` feature. [Pull Request #2702](https://github.com/projectlombok/lombok/pull/2702). +* IMPROBABLE BREAKING CHANGE: If the underlying compiler and `--release` / `--source` option is 10 or higher, lombok's `val` is now replaced by `final var`. That means compound declarations such as `val x = 10, y = 12;` now fail (lombok's old `val` implementation supported it, javac's `var` does not), but IDE support in particular is more reliable. We decided it was worth the tradeoff. +* BUGFIX: Syntax highlighting in VSCode now works reliably when using lombok. [Issue #2950](https://github.com/projectlombok/lombok/issues/2950). +* BUGFIX: Eclipse's _organize imports_ feature would sometimes remove your `lombok.val` import. [Issue #2972](https://github.com/projectlombok/lombok/issues/2972). + ### v1.18.20 (April 2nd, 2021) * PLATFORM: JDK16 support added. [Issue #2681](https://github.com/projectlombok/lombok/issues/2681). diff --git a/doc/debug-insights/eclipse.txt b/doc/debug-insights/eclipse.txt new file mode 100644 index 00000000..b653594a --- /dev/null +++ b/doc/debug-insights/eclipse.txt @@ -0,0 +1,22 @@ +# How to debug lombok running in eclipse + +## Overview + +Lombok's build scripting can generate a target for you, that lets you run the same eclipse installation inside eclipse, in debug mode. Now you can add breakpoints. + +As lombok is an agent, lombok __must__ load from a jar file. +Nevertheless, lombok can be hot-code-replaced in the debugger. +This works via the loader: The lombok agent has its own classloading architecture, and this architecture is capable of loading lombok's class files from a location of your choosing. Choose the /bin dir from your eclipse project which will help with debugging; eclipse will then be able to apply HCR to the eclipse-running-in-eclipse. Unless there are issues with the loader architecture itself, of course. + +The end goal is that you can make some changes to the lombok sources in your eclipse, then click the 'debug' button, and a new 'test eclipse' starts up using lombok as you wrote it just now. You can now make changes to lombok sources in the original eclipse, hit 'save', and these changes now get automatically applied to the 'test eclipse', as long as you aren't making any changes to signatures (add or remove methods/fields/types, or change return types, param types, etc). + +If you have the sources to eclipse itself, you can open them, set breakpoints, and step through, though be aware that lombok's agent injection system does cause some issues here; we move methods into different classes and eclipse's debugger naturally doesn't understand this, so you can't breakpoint lombok's own patch methods, and stepping through them 'works' but looks bizarre in the debugger as the debugger now thinks your source file clearly cannot possibly match the class file currently running. Just keep going ('step out'), eclipse will figure it out again once you're back in un-instrumented eclipse code. + + +TODO: + +Describe in detail: + +* Which ant tasks to run to create the targets +* How to modify this target, if needed, to point at your bin dir + diff --git a/doc/debug-insights/vscode.txt b/doc/debug-insights/vscode.txt new file mode 100644 index 00000000..efc55619 --- /dev/null +++ b/doc/debug-insights/vscode.txt @@ -0,0 +1,7 @@ +As per @Rawi01's experimenting: + +* VSCode's lombok plugin simply adds the appropriate `-javaagent` options when it fires up the eclipse-based language server. You can also add debug flags here. +* Add the flags `-agentlib:jdwp-transport=dt_socket,server=y,suspend=n,quiet=y,address=12345` to the `settings.json` of the VSCode lombok plugin, and then tell your debugger to attach to localhost:12345. +* Set the property `java.server.launchMode` to `"Standard"`. +* Consider activing the language server debug mode. + diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index b8cd442a..05550a06 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-2021 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,6 +24,7 @@ package lombok; import java.util.List; import lombok.core.configuration.CallSuperType; +import lombok.core.configuration.CapitalizationStrategy; import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; @@ -558,6 +559,15 @@ public class ConfigurationKeys { */ public static final ConfigurationKey<Boolean> ACCESSORS_FLUENT = new ConfigurationKey<Boolean>("lombok.accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix) (default: false).") {}; + /** + * lombok configuration: {@code lombok.accessors.capitalization} = {@code basic} | {@code beanspec}. + * + * Which capitalization rule is used to turn field names into getter/setter/with names and vice versa for field names that start with 1 lowercase letter, then 1 uppercase letter. + * basic = {@code uShape} becomes {@code getUShape}, beanspec = {@code uShape} becomes {@code getuShape} (default = basic). + */ + public static final ConfigurationKey<CapitalizationStrategy> ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION = new ConfigurationKey<CapitalizationStrategy>("lombok.accessors.capitalization", "Which capitalization strategy to use when converting field names to accessor names and vice versa (default: basic).") {}; + + // ----- ExtensionMethod ----- /** diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java index 9f3a471f..07d035c5 100755 --- a/src/core/lombok/core/AST.java +++ b/src/core/lombok/core/AST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2019 The Project Lombok Authors. + * Copyright (C) 2009-2021 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 @@ -430,6 +430,9 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, } } + /** + * @return The {@code lombok.config} configuration value for the provided {@code key}, or {@code null} if that key is not in the config / there is no config. + */ public final <T> T readConfiguration(ConfigurationKey<T> key) { long start = configTracker == null ? 0L : configTracker.start(); try { @@ -438,4 +441,17 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, if (configTracker != null) configTracker.end(start); } } + + /** + * @return The {@code lombok.config} configuration value for the provided {@code key}, or {@code defaultValue} if that key is not in the config / there is no config. + */ + public final <T> T readConfigurationOr(ConfigurationKey<T> key, T defaultValue) { + long start = configTracker == null ? 0L : configTracker.start(); + try { + T value = LombokConfiguration.read(key, this); + return value != null ? value : defaultValue; + } finally { + if (configTracker != null) configTracker.end(start); + } + } } diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index eb8ed6e7..dafe17ae 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -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.21"; + private static final String VERSION = "1.18.23"; private static final String RELEASE_NAME = "Edgy Guinea Pig"; // private static final String RELEASE_NAME = "Envious Ferret"; diff --git a/src/core/lombok/core/configuration/CapitalizationStrategy.java b/src/core/lombok/core/configuration/CapitalizationStrategy.java new file mode 100644 index 00000000..affd3576 --- /dev/null +++ b/src/core/lombok/core/configuration/CapitalizationStrategy.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.core.configuration; + +/** Used for lombok configuration to determine how to transform field names when turning them into accessor method names and vice versa. */ +public enum CapitalizationStrategy { + BASIC { + @Override public String capitalize(String in) { + if (in.length() == 0) return in; + char first = in.charAt(0); + if (!Character.isLowerCase(first)) return in; + boolean useUpperCase = in.length() > 2 && + (Character.isTitleCase(in.charAt(1)) || Character.isUpperCase(in.charAt(1))); + return (useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first)) + in.substring(1); + } + }, + BEANSPEC { + @Override public String capitalize(String in) { + if (in.length() == 0) return in; + char first = in.charAt(0); + if (!Character.isLowerCase(first) || (in.length() > 1 && Character.isUpperCase(in.charAt(1)))) return in; + boolean useUpperCase = in.length() > 2 && Character.isTitleCase(in.charAt(1)); + return (useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first)) + in.substring(1); + } + }, + ; + + public static CapitalizationStrategy defaultValue() { + return BASIC; + } + + public abstract String capitalize(String in); +} diff --git a/src/core/lombok/core/configuration/FlagUsageType.java b/src/core/lombok/core/configuration/FlagUsageType.java index 8717c22b..293a2f1d 100644 --- a/src/core/lombok/core/configuration/FlagUsageType.java +++ b/src/core/lombok/core/configuration/FlagUsageType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-2021 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.core.configuration; -/** Used for lombok configuration to flag usages of certain lombok feature. */ +/** Used for lombok configuration to flag usages of certain lombok features. */ public enum FlagUsageType { WARNING, ERROR, ALLOW; } diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index f57d83c2..f90a7caf 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-2021 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 @@ -46,6 +46,7 @@ import lombok.core.AnnotationValues; import lombok.core.JavaIdentifiers; import lombok.core.LombokNode; import lombok.core.configuration.AllowHelper; +import lombok.core.configuration.CapitalizationStrategy; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; import lombok.experimental.Accessors; @@ -431,6 +432,7 @@ public class HandlerUtil { "com.fasterxml.jackson.annotation.JsonSetter", "com.fasterxml.jackson.annotation.JsonSubTypes", "com.fasterxml.jackson.annotation.JsonTypeInfo", + "com.fasterxml.jackson.annotation.JsonUnwrapped", "com.fasterxml.jackson.annotation.JsonView", "com.fasterxml.jackson.databind.annotation.JsonDeserialize", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper", @@ -692,11 +694,13 @@ public class HandlerUtil { if (Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.GETTER_CONSEQUENT_BOOLEAN))) isBoolean = false; boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix"); boolean explicitFluent = accessors != null && accessors.isExplicit("fluent"); + boolean explicitJavaBeansSpecCapitalization = accessors != null && accessors.isExplicit("javaBeansSpecCapitalization"); - Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null; + Accessors ac = (explicitPrefix || explicitFluent || explicitJavaBeansSpecCapitalization) ? accessors.getInstance() : null; List<String> prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); + CapitalizationStrategy capitalizationStrategy = ast.readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return null; @@ -709,7 +713,7 @@ public class HandlerUtil { return booleanPrefix + fName.substring(2); } - return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName); + return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName, capitalizationStrategy); } /** @@ -787,6 +791,7 @@ public class HandlerUtil { List<String> prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); + CapitalizationStrategy capitalizationStrategy = ast.readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return Collections.emptyList(); @@ -798,8 +803,8 @@ public class HandlerUtil { if (adhereToFluent && fluent) { names.add(baseName); } else { - names.add(buildAccessorName(normalPrefix, baseName)); - if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName)); + names.add(buildAccessorName(normalPrefix, baseName, capitalizationStrategy)); + if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName, capitalizationStrategy)); } } @@ -825,23 +830,36 @@ public class HandlerUtil { } /** + * @param node Any node (used to fetch config of capitalization strategy). + * @param prefix Something like {@code get} or {@code set} or {@code is}. + * @param suffix Something like {@code running}. + * @return prefix + smartly title-cased suffix. For example, {@code setRunning}. + */ + public static String buildAccessorName(AST<?, ?, ?> ast, String prefix, String suffix) { + CapitalizationStrategy capitalizationStrategy = ast.readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); + return buildAccessorName(prefix, suffix, capitalizationStrategy); + } + + /** + * @param node Any node (used to fetch config of capitalization strategy). * @param prefix Something like {@code get} or {@code set} or {@code is}. * @param suffix Something like {@code running}. * @return prefix + smartly title-cased suffix. For example, {@code setRunning}. */ - public static String buildAccessorName(String prefix, String suffix) { + public static String buildAccessorName(LombokNode<?, ?, ?> node, String prefix, String suffix) { + CapitalizationStrategy capitalizationStrategy = node.getAst().readConfigurationOr(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION, CapitalizationStrategy.defaultValue()); + return buildAccessorName(prefix, suffix, capitalizationStrategy); + } + + /** + * @param prefix Something like {@code get} or {@code set} or {@code is}. + * @param suffix Something like {@code running}. + * @param capitalizationStrategy Which strategy to use to capitalize the name part. + */ + private static String buildAccessorName(String prefix, String suffix, CapitalizationStrategy capitalizationStrategy) { if (suffix.length() == 0) return prefix; if (prefix.length() == 0) return suffix; - - char first = suffix.charAt(0); - if (Character.isLowerCase(first)) { - boolean useUpperCase = suffix.length() > 2 && - (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1))); - suffix = String.format("%s%s", - useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first), - suffix.subSequence(1, suffix.length())); - } - return String.format("%s%s", prefix, suffix); + return prefix + capitalizationStrategy.capitalize(suffix); } public static String camelCaseToConstant(String fieldName) { diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index 4f86f0a5..4950aeef 100644 --- a/src/core/lombok/eclipse/EclipseNode.java +++ b/src/core/lombok/eclipse/EclipseNode.java @@ -215,13 +215,16 @@ public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode, @Override public boolean isStatic() { if (node instanceof TypeDeclaration) { + TypeDeclaration t = (TypeDeclaration) node; + int f = t.modifiers; + if (((ClassFileConstants.AccInterface | ClassFileConstants.AccEnum) & f) != 0) return true; + EclipseNode directUp = directUp(); if (directUp == null || directUp.getKind() == Kind.COMPILATION_UNIT) return true; if (!(directUp.get() instanceof TypeDeclaration)) return false; TypeDeclaration p = (TypeDeclaration) directUp.get(); - int f = p.modifiers; - if ((ClassFileConstants.AccInterface & f) != 0) return true; - if ((ClassFileConstants.AccEnum & f) != 0) return true; + f = p.modifiers; + if (((ClassFileConstants.AccInterface | ClassFileConstants.AccEnum) & f) != 0) return true; } if (node instanceof FieldDeclaration) { diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 5eea980c..f8cde6c8 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -95,6 +95,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; @@ -337,6 +338,8 @@ public class EclipseHandlerUtil { public static final Class<?> INTERSECTION_BINDING1, INTERSECTION_BINDING2; public static final Field INTERSECTION_BINDING_TYPES1, INTERSECTION_BINDING_TYPES2; public static final Field TYPE_DECLARATION_RECORD_COMPONENTS; + public static final Class<?> COMPILATION_UNIT; + public static final Method COMPILATION_UNIT_ORIGINAL_FROM_CLONE; static { STRING_LITERAL__LINE_NUMBER = getField(StringLiteral.class, "lineNumber"); ANNOTATION__MEMBER_VALUE_PAIR_NAME = getField(Annotation.class, "memberValuePairName"); @@ -346,6 +349,8 @@ public class EclipseHandlerUtil { INTERSECTION_BINDING_TYPES1 = INTERSECTION_BINDING1 == null ? null : getField(INTERSECTION_BINDING1, "intersectingTypes"); INTERSECTION_BINDING_TYPES2 = INTERSECTION_BINDING2 == null ? null : getField(INTERSECTION_BINDING2, "intersectingTypes"); TYPE_DECLARATION_RECORD_COMPONENTS = getField(TypeDeclaration.class, "recordComponents"); + COMPILATION_UNIT = getClass("org.eclipse.jdt.internal.core.CompilationUnit"); + COMPILATION_UNIT_ORIGINAL_FROM_CLONE = COMPILATION_UNIT == null ? null : Permit.permissiveGetMethod(COMPILATION_UNIT, "originalFromClone"); } public static int reflectInt(Field f, Object o) { @@ -1042,7 +1047,7 @@ public class EclipseHandlerUtil { res[count] = name; n = parent; - while (n != null && n.getKind() == Kind.TYPE && n.get() instanceof TypeDeclaration) { + while (count > 0) { TypeDeclaration td = (TypeDeclaration) n.get(); res[--count] = td.name; n = n.up(); @@ -2052,11 +2057,7 @@ public class EclipseHandlerUtil { } int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; - long[] poss = new long[annotationTypeFqn.length]; - Arrays.fill(poss, p); - QualifiedTypeReference qualifiedType = new QualifiedTypeReference(annotationTypeFqn, poss); - setGeneratedBy(qualifiedType, source); + TypeReference qualifiedType = generateQualifiedTypeRef(source, annotationTypeFqn); Annotation ann; if (args != null && args.length == 1 && args[0] instanceof Expression) { SingleMemberAnnotation sma = new SingleMemberAnnotation(qualifiedType, pS); @@ -2636,6 +2637,13 @@ public class EclipseHandlerUtil { } /** + * Returns {@code true} if the provided node is an actual class, an enum or a record and not some other type declaration (so, not an annotation definition or interface). + */ + public static boolean isClassEnumOrRecord(EclipseNode typeNode) { + return isTypeAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation); + } + + /** * Returns {@code true} if the provided node is a record declaration (so, not an annotation definition, interface, enum, or plain class). */ public static boolean isRecord(EclipseNode typeNode) { @@ -2662,6 +2670,21 @@ public class EclipseHandlerUtil { return (modifiers & flags) == 0; } + /** + * Returns {@code true} if the provided node supports static methods and types (top level or static class) + */ + public static boolean isStaticAllowed(EclipseNode typeNode) { + boolean staticAllowed = true; + + while (typeNode.getKind() != Kind.COMPILATION_UNIT) { + if (!staticAllowed) return false; + + staticAllowed = typeNode.isStatic(); + typeNode = typeNode.up(); + } + return true; + } + public static AbstractVariableDeclaration[] getRecordComponents(TypeDeclaration typeDeclaration) { if (typeDeclaration == null || (typeDeclaration.modifiers & AccRecord) == 0) return null; try { @@ -2713,7 +2736,14 @@ public class EclipseHandlerUtil { public static void setDocComment(CompilationUnitDeclaration cud, TypeDeclaration type, ASTNode node, String doc) { if (doc == null) return; - Map<String, String> docs = EcjAugments.CompilationUnit_javadoc.setIfAbsent(cud.compilationResult.compilationUnit, new HashMap<String, String>()); + ICompilationUnit compilationUnit = cud.compilationResult.compilationUnit; + if (compilationUnit.getClass().equals(COMPILATION_UNIT)) { + try { + compilationUnit = (ICompilationUnit) Permit.invoke(COMPILATION_UNIT_ORIGINAL_FROM_CLONE, compilationUnit); + } catch (Throwable t) { } + } + + Map<String, String> docs = EcjAugments.CompilationUnit_javadoc.setIfAbsent(compilationUnit, new HashMap<String, String>()); if (node instanceof AbstractMethodDeclaration) { AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; String signature = getSignature(type, methodDeclaration); diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index dab774f3..2bfe1e8b 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -293,6 +293,11 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { List<EclipseNode> nonFinalNonDefaultedFields = null; + if (!isStaticAllowed(upToTypeNode(parent))) { + annotationNode.addError("@Builder is not supported on non-static nested classes."); + return; + } + if (parent.get() instanceof TypeDeclaration) { if (!isClass(parent) && !isRecord(parent)) { annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR); @@ -660,7 +665,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { for (BuilderFieldData bfd : job.builderFields) { String setterName = new String(bfd.name); String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; - if (!setterPrefix.isEmpty()) setterName = HandlerUtil.buildAccessorName(setterPrefix, setterName); + if (!setterPrefix.isEmpty()) setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, setterName); MessageSend ms = new MessageSend(); Expression[] tgt = new Expression[bfd.singularData == null ? 1 : 2]; @@ -1028,9 +1033,9 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { String setterPrefix = prefix.isEmpty() ? "set" : prefix; String setterName; if (job.oldFluent) { - setterName = prefix.isEmpty() ? new String(bfd.name) : HandlerUtil.buildAccessorName(setterPrefix, new String(bfd.name)); + setterName = prefix.isEmpty() ? new String(bfd.name) : HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, new String(bfd.name)); } else { - setterName = HandlerUtil.buildAccessorName(setterPrefix, new String(bfd.name)); + setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, new String(bfd.name)); } for (int i = 0; i < len; i++) { diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 12a3c315..a5e8dfb5 100755 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -538,14 +538,15 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH if (addWildcards) genericsCount.add(arraySizeOf(((TypeDeclaration) type.get()).typeParameters)); boolean staticContext = (((TypeDeclaration) type.get()).modifiers & ClassFileConstants.AccStatic) != 0; EclipseNode tNode = type.up(); - if (!staticContext && tNode.getKind() == Kind.TYPE && (((TypeDeclaration) tNode.get()).modifiers & ClassFileConstants.AccInterface) != 0) staticContext = true; while (tNode != null && tNode.getKind() == Kind.TYPE) { + TypeDeclaration td = (TypeDeclaration) tNode.get(); + if (td.name == null || td.name.length == 0) break; list.add(tNode.getName()); - if (addWildcards) genericsCount.add(staticContext ? 0 : arraySizeOf(((TypeDeclaration) tNode.get()).typeParameters)); - if (!staticContext) staticContext = (((TypeDeclaration) tNode.get()).modifiers & Modifier.STATIC) != 0; + if (!staticContext && tNode.getKind() == Kind.TYPE && (td.modifiers & ClassFileConstants.AccInterface) != 0) staticContext = true; + if (addWildcards) genericsCount.add(staticContext ? 0 : arraySizeOf(td.typeParameters)); + if (!staticContext) staticContext = (td.modifiers & Modifier.STATIC) != 0; tNode = tNode.up(); - if (!staticContext && tNode.getKind() == Kind.TYPE && (((TypeDeclaration) tNode.get()).modifiers & ClassFileConstants.AccInterface) != 0) staticContext = true; } Collections.reverse(list); if (addWildcards) Collections.reverse(genericsCount); diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java index 5900e7ed..3297ba06 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java @@ -160,6 +160,8 @@ public class HandleFieldDefaults extends EclipseASTAdapter { boolean defaultToFinal = makeFinalIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE)); if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return; + // Do not apply field defaults to records if set using the the config system + if (fieldDefaults == null && !isClassOrEnum(typeNode)) return; AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null; boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal; diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index cc1a5c3f..071dcdfb 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -60,14 +60,12 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName private static final IdentifierName FIELDS = IdentifierName.valueOf("Fields"); public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, boolean asEnum, IdentifierName innerTypeName, boolean onlyExplicit, boolean uppercase) { - TypeDeclaration typeDecl = null; - if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get(); - - int modifiers = typeDecl == null ? 0 : typeDecl.modifiers; - boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; - - if (typeDecl == null || notAClass) { - errorNode.addError("@FieldNameConstants is only supported on a class or an enum."); + if (!isClassEnumOrRecord(typeNode)) { + errorNode.addError("@FieldNameConstants is only supported on a class, an enum or a record."); + return; + } + if (!isStaticAllowed(typeNode)) { + errorNode.addError("@FieldNameConstants is not supported on non-static nested classes."); return; } diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index 1cac2de7..db9104ef 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -88,6 +88,11 @@ public class HandleLog { return; } + if (useStatic && !isStaticAllowed(owner)) { + annotationNode.addError(framework.getAnnotationAsString() + " is not supported on non-static nested classes."); + return; + } + Object valueGuess = annotation.getValueGuess("topic"); Expression loggerTopic = (Expression) annotation.getActualExpression("topic"); diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 4d5d2448..26b62cbf 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -184,6 +184,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { annotationNode.addError("@SuperBuilder is only supported on classes."); return; } + if (!isStaticAllowed(parent)) { + annotationNode.addError("@SuperBuilder is not supported on non-static nested classes."); + return; + } job.parentType = parent; TypeDeclaration td = (TypeDeclaration) parent.get(); @@ -794,7 +798,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } private MessageSend createSetterCallWithInstanceValue(BuilderFieldData bfd, EclipseNode type, ASTNode source, String setterPrefix) { - char[] setterName = HandlerUtil.buildAccessorName(setterPrefix, String.valueOf(bfd.name)).toCharArray(); + char[] setterName = HandlerUtil.buildAccessorName(type, setterPrefix, String.valueOf(bfd.name)).toCharArray(); MessageSend ms = new MessageSend(); Expression[] tgt = new Expression[bfd.singularData == null ? 1 : 2]; @@ -1000,7 +1004,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { if (existing == null) existing = EMPTY_METHODS; int len = existing.length; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, new String(paramName)); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, new String(paramName)); for (int i = 0; i < len; i++) { if (!(existing[i] instanceof MethodDeclaration)) continue; diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java index 171402b3..05b0e069 100644 --- a/src/core/lombok/eclipse/handlers/HandleToString.java +++ b/src/core/lombok/eclipse/handlers/HandleToString.java @@ -315,7 +315,9 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { String typeName = getSingleTypeName(type); EclipseNode upType = type.up(); while (upType.getKind() == Kind.TYPE) { - typeName = getSingleTypeName(upType) + "." + typeName; + String upTypeName = getSingleTypeName(upType); + if (upTypeName.isEmpty()) break; + typeName = upTypeName + "." + typeName; upType = upType.up(); } return typeName; diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index ac53e27e..1bea5525 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -23,6 +23,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.eclipse.handlers.EclipseHandlerUtil.typeMatches; + import lombok.ConfigurationKeys; import lombok.val; import lombok.var; @@ -42,7 +43,7 @@ import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.TypeReference; /* - * This class just handles 3 basic error cases. The real meat of eclipse 'val' support is in {@code PatchVal} and {@code PatchValEclipse}. + * This class just handles 3 basic error cases. The real meat of eclipse 'val' support is in {@code PatchVal} and {@code PatchValEclipse} */ @Provides(EclipseASTVisitor.class) @DeferUntilPostDiet diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 7dcf18c9..9b464a25 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -126,7 +126,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); thisDotField.receiver = new ThisReference(0, 0); Assignment a = new Assignment(thisDotField, new NullLiteral(0, 0), 0); - md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + md.selector = HandlerUtil.buildAccessorName(builderType, "clear", new String(data.getPluralName())).toCharArray(); md.statements = returnStatement != null ? new Statement[] {a, returnStatement} : new Statement[] {a}; md.returnType = returnType; md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); @@ -173,8 +173,8 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { md.arguments[i].annotations = typeUseAnns; } md.returnType = returnType; - char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); - md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray(); + char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); + md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName(builderType, "add", new String(data.getSingularName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); @@ -213,8 +213,8 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { md.arguments = new Argument[] {param}; md.returnType = returnType; - char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); - md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray(); + char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); + md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName(builderType, "addAll", new String(data.getPluralName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index 882b7adc..6f5e9add 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -112,7 +112,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula thisDotField.receiver = new ThisReference(0, 0); FieldReference thisDotField2 = new FieldReference(data.getPluralName(), 0L); thisDotField2.receiver = new ThisReference(0, 0); - md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + md.selector = HandlerUtil.buildAccessorName(builderType, "clear", new String(data.getPluralName())).toCharArray(); MessageSend clearMsg = new MessageSend(); clearMsg.receiver = thisDotField2; clearMsg.selector = "clear".toCharArray(); @@ -151,8 +151,8 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula param.annotations = typeUseAnns; md.arguments = new Argument[] {param}; md.returnType = returnType; - char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); - md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray(); + char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray(); + md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName(builderType, "add", new String(data.getSingularName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); @@ -189,8 +189,8 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula md.arguments = new Argument[] {param}; md.returnType = returnType; - char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); - md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray(); + char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray(); + md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName(builderType, "addAll", new String(data.getPluralName())).toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index a766612f..c28ba59d 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -177,7 +177,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer thisDotField2.receiver = new ThisReference(0, 0); FieldReference thisDotField3 = new FieldReference(valueFieldName, 0L); thisDotField3.receiver = new ThisReference(0, 0); - md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + md.selector = HandlerUtil.buildAccessorName(builderType, "clear", new String(data.getPluralName())).toCharArray(); MessageSend clearMsg1 = new MessageSend(); clearMsg1.receiver = thisDotField2; clearMsg1.selector = "clear".toCharArray(); @@ -249,7 +249,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer String name = new String(data.getSingularName()); String setterPrefix = data.getSetterPrefix().length > 0 ? new String(data.getSetterPrefix()) : fluent ? "" : "put"; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, name); + String setterName = HandlerUtil.buildAccessorName(builderType, setterPrefix, name); md.selector = setterName.toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); @@ -325,7 +325,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer String name = new String(data.getPluralName()); String setterPrefix = data.getSetterPrefix().length > 0 ? new String(data.getSetterPrefix()) : fluent ? "" : "put"; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, name); + String setterName = HandlerUtil.buildAccessorName(builderType, setterPrefix, name); md.selector = setterName.toCharArray(); Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index f58de60f..0919c7d4 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -228,7 +228,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { int underscoreIdx = nm.indexOf('_'); if (underscoreIdx > -1) return Integer.parseInt(nm.substring(underscoreIdx + 1)); // assume java9+ - return Integer.parseInt(nm); + return Integer.parseInt(nm.substring(3)); } catch (Exception ignore) {} return 6; } diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index 035f7c53..fca0d0d1 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -286,13 +286,15 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre @Override public boolean isStatic() { if (node instanceof JCClassDecl) { + JCClassDecl t = (JCClassDecl) node; + long f = t.mods.flags; + if (((Flags.INTERFACE | Flags.ENUM) & f) != 0) return true; JavacNode directUp = directUp(); if (directUp == null || directUp.getKind() == Kind.COMPILATION_UNIT) return true; if (!(directUp.get() instanceof JCClassDecl)) return false; JCClassDecl p = (JCClassDecl) directUp.get(); - long f = p.mods.flags; - if ((Flags.INTERFACE & f) != 0) return true; - if ((Flags.ENUM & f) != 0) return true; + f = p.mods.flags; + if (((Flags.INTERFACE | Flags.ENUM) & f) != 0) return true; } if (node instanceof JCVariableDecl) { diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index c23dc14c..d8fdfb1b 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -234,6 +234,11 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { ArrayList<JavacNode> nonFinalNonDefaultedFields = null; + if (!isStaticAllowed(upToTypeNode(parent))) { + annotationNode.addError("@Builder is not supported on non-static nested classes."); + return; + } + if (parent.get() instanceof JCClassDecl) { if (!isClass(parent) && !isRecord(parent)) { annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR); @@ -631,7 +636,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { for (BuilderFieldData bfd : job.builderFields) { String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; String prefixedSetterName = bfd.name.toString(); - if (!setterPrefix.isEmpty()) prefixedSetterName = HandlerUtil.buildAccessorName(setterPrefix, prefixedSetterName); + if (!setterPrefix.isEmpty()) prefixedSetterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, prefixedSetterName); Name setterName = job.toName(prefixedSetterName); JCExpression[] tgt = new JCExpression[bfd.singularData == null ? 1 : 2]; @@ -896,7 +901,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { private void makePrefixedSetterMethodForBuilder(BuilderJob job, BuilderFieldData bfd, boolean deprecate, String prefix) { JavacNode fieldNode = bfd.createdFields.get(0); String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, bfd.name.toString()); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, bfd.name.toString()); Name setterName_ = job.builderType.toName(setterName); for (JavacNode child : job.builderType.down()) { diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index ffe882d8..dace3521 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -385,7 +385,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas boolean staticContext = (((JCClassDecl) type.get()).getModifiers().flags & Flags.STATIC) != 0; JavacNode tNode = type.up(); - while (tNode != null && tNode.getKind() == Kind.TYPE) { + while (tNode != null && tNode.getKind() == Kind.TYPE && !tNode.getName().isEmpty()) { list.add(tNode.getName()); if (addWildcards) genericsCount.add(staticContext ? 0 : ((JCClassDecl) tNode.get()).typarams.size()); if (!staticContext) staticContext = (((JCClassDecl) tNode.get()).getModifiers().flags & Flags.STATIC) != 0; diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index ebab67e3..9a6632dd 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -140,6 +140,8 @@ public class HandleFieldDefaults extends JavacASTAdapter { boolean defaultToFinal = makeFinalIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE)); if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return; + // Do not apply field defaults to records if set using the the config system + if (fieldDefaults == null && !isClassOrEnum(typeNode)) return; AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null; boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal; diff --git a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java index f3c879d5..1fc6beb1 100644 --- a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java @@ -57,14 +57,12 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo private static final IdentifierName FIELDS = IdentifierName.valueOf("Fields"); public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean asEnum, IdentifierName innerTypeName, boolean onlyExplicit, boolean uppercase) { - JCClassDecl typeDecl = null; - if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get(); - - long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags; - boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0; - - if (typeDecl == null || notAClass) { - errorNode.addError("@FieldNameConstants is only supported on a class or an enum."); + if (!isClassEnumOrRecord(typeNode)) { + errorNode.addError("@FieldNameConstants is only supported on a class, an enum or a record."); + return; + } + if (!isStaticAllowed(typeNode)) { + errorNode.addError("@FieldNameConstants is not supported on non-static nested classes."); return; } diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 40f7ff08..957f5581 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -80,6 +80,11 @@ public class HandleLog { return; } + if (useStatic && !isStaticAllowed(typeNode)) { + annotationNode.addError(framework.getAnnotationAsString() + " is not supported on non-static nested classes."); + return; + } + Object valueGuess = annotation.getValueGuess("topic"); JCExpression loggerTopic = (JCExpression) annotation.getActualExpression("topic"); diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java index fe66432a..271bedbb 100644 --- a/src/core/lombok/javac/handlers/HandleNonNull.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.java @@ -99,7 +99,6 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { return recursiveSetGeneratedBy(constr, source); } else { existingCtr.mods = mods; - existingCtr.params = params.toList(); existingCtr.body = body; existingCtr = recursiveSetGeneratedBy(existingCtr, source); addSuppressWarningsAll(existingCtr.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(existingCtr)), typeNode.getContext()); diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index a0634494..e5b2c062 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -43,7 +43,6 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCAssign; import com.sun.tools.javac.tree.JCTree.JCBlock; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCReturn; diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 87b18576..b5bc73fb 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -163,6 +163,10 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { annotationNode.addError("@SuperBuilder is only supported on classes."); return; } + if (!isStaticAllowed(parent)) { + annotationNode.addError("@SuperBuilder is not supported on non-static nested classes."); + return; + } job.parentType = parent; JCClassDecl td = (JCClassDecl) parent.get(); @@ -773,7 +777,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { arg = maker.Conditional(eqNull, emptyCollection, tgt[1]); } - String setterName = HandlerUtil.buildAccessorName(setterPrefix, bfd.name.toString()); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, bfd.name.toString()); JCMethodInvocation apply = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(job.toName(BUILDER_VARIABLE_NAME)), job.toName(setterName)), List.of(arg)); JCExpressionStatement exec = maker.Exec(apply); return exec; @@ -945,7 +949,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } private void generateSimpleSetterMethodForBuilder(SuperBuilderJob job, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JCExpression returnType, JCStatement returnStatement, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, String setterPrefix) { - String setterName = HandlerUtil.buildAccessorName(setterPrefix, paramName.toString()); + String setterName = HandlerUtil.buildAccessorName(job.sourceNode, setterPrefix, paramName.toString()); Name setterName_ = job.builderType.toName(setterName); for (JavacNode child : job.builderType.down()) { diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index 3fc6a4e4..249993ee 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -44,7 +44,6 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBlock; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; @@ -252,10 +251,10 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { } public static String getTypeName(JavacNode typeNode) { - String typeName = ((JCClassDecl) typeNode.get()).name.toString(); + String typeName = typeNode.getName(); JavacNode upType = typeNode.up(); - while (upType.getKind() == Kind.TYPE) { - typeName = ((JCClassDecl) upType.get()).name.toString() + "." + typeName; + while (upType.getKind() == Kind.TYPE && !upType.getName().isEmpty()) { + typeName = upType.getName() + "." + typeName; upType = upType.up(); } return typeName; diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 0ed831ab..d4fb1027 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -115,6 +115,12 @@ public class HandleVal extends JavacASTAdapter { local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); } + if (localNode.getSourceVersion() >= 10) { + local.vartype = null; + localNode.getAst().setChanged(); + return; + } + if (JavacResolution.platformHasTargetTyping()) { local.vartype = localNode.getAst().getTreeMaker().Ident(localNode.getAst().toName("___Lombok_VAL_Attrib__")); } else { diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 78c20d39..a41264e8 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -106,6 +106,7 @@ import lombok.javac.Javac; import lombok.javac.JavacAugments; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.javac.JavacTreeMaker.TypeTag; import lombok.permit.Permit; /** @@ -1286,6 +1287,7 @@ public class JavacHandlerUtil { static Type classEnter(JCTree tree, JavacNode parent) { Enter enter = Enter.instance(parent.getContext()); Env<AttrContext> classEnv = enter.getEnv((TypeSymbol) parent.getElement()); + if (classEnv == null) return null; Type type = (Type) Permit.invokeSneaky(classEnter, enter, tree, classEnv); if (type == null) return null; type.complete(); @@ -1902,7 +1904,7 @@ public class JavacHandlerUtil { public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode parentType, Name typeName, boolean instance, List<JCTypeParameter> params, List<JCAnnotation> annotations) { JCExpression r = null; - if (parentType != null && parentType.getKind() == Kind.TYPE) { + if (parentType != null && parentType.getKind() == Kind.TYPE && !parentType.getName().isEmpty()) { JCClassDecl td = (JCClassDecl) parentType.get(); boolean outerInstance = instance && ((td.mods.flags & Flags.STATIC) == 0); List<JCTypeParameter> outerParams = instance ? td.typarams : List.<JCTypeParameter>nil(); @@ -1979,6 +1981,13 @@ public class JavacHandlerUtil { } /** + * Returns {@code true} if the provided node is an actual class, an enum or a record and not some other type declaration (so, not an annotation definition or interface). + */ + public static boolean isClassEnumOrRecord(JavacNode typeNode) { + return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ANNOTATION); + } + + /** * Returns {@code true} if the provided node is a record declaration (so, not an annotation definition, interface, enum, or plain class). */ public static boolean isRecord(JavacNode typeNode) { @@ -1994,6 +2003,21 @@ public class JavacHandlerUtil { return (typeDeclflags & flags) == 0; } + /** + * Returns {@code true} if the provided node supports static methods and types (top level or static class) + */ + public static boolean isStaticAllowed(JavacNode typeNode) { + boolean staticAllowed = true; + + while (typeNode.getKind() != Kind.COMPILATION_UNIT) { + if (!staticAllowed) return false; + + staticAllowed = typeNode.isStatic(); + typeNode = typeNode.up(); + } + return true; + } + public static JavacNode upToTypeNode(JavacNode node) { if (node == null) throw new NullPointerException("node"); while ((node != null) && !(node.get() instanceof JCClassDecl)) node = node.up(); @@ -2028,7 +2052,9 @@ public class JavacHandlerUtil { private static JCExpression cloneType0(JavacTreeMaker maker, JCTree in) { if (in == null) return null; - if (in instanceof JCPrimitiveTypeTree) return (JCExpression) in; + if (in instanceof JCPrimitiveTypeTree) { + return maker.TypeIdent(TypeTag.typeTag(in)); + } if (in instanceof JCIdent) { return maker.Ident(((JCIdent) in).name); diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 4ca09b82..77fcd4ea 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -300,7 +300,7 @@ public class JavacSingularsRecipes { ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); statements.append(clearStatement); - Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); + Name methodName = builderType.toName(HandlerUtil.buildAccessorName(source, "clear", data.getPluralName().toString())); finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.<JCVariableDecl>nil(), List.<JCAnnotation>nil(), access, null); } @@ -312,7 +312,7 @@ public class JavacSingularsRecipes { Name name = data.getSingularName(); String setterPrefix = data.getSetterPrefix(); if (setterPrefix.isEmpty() && !fluent) setterPrefix = getAddMethodName(); - if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(setterPrefix, name.toString())); + if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(source, setterPrefix, name.toString())); statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source)); List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up())); @@ -344,7 +344,7 @@ public class JavacSingularsRecipes { Name name = data.getPluralName(); String setterPrefix = data.getSetterPrefix(); if (setterPrefix.isEmpty() && !fluent) setterPrefix = getAddMethodName() + "All"; - if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(setterPrefix, name.toString())); + if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(source, setterPrefix, name.toString())); JCExpression paramType = getPluralMethodParamType(builderType); paramType = addTypeArgs(getTypeArgumentsCount(), true, builderType, paramType, data.getTypeArgs(), source); long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 8d39f447..e4f17602 100755 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -43,9 +43,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -733,7 +733,7 @@ public class Delombok { List<JCCompilationUnit> roots = new ArrayList<JCCompilationUnit>(); Map<JCCompilationUnit, File> baseMap = new IdentityHashMap<JCCompilationUnit, File>(); - Set<AbstractProcessor> processors = new HashSet<AbstractProcessor>(); + Set<AbstractProcessor> processors = new LinkedHashSet<AbstractProcessor>(); processors.add(new lombok.javac.apt.LombokProcessor()); processors.addAll(additionalAnnotationProcessors); diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index bcf3f431..605b9391 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -545,6 +545,12 @@ public class PrettyPrinter extends JCTree.Visitor { print(tree.implementing, ", "); } + List<JCExpression> permitting = readObject(tree, "permitting", List.<JCExpression>nil()); + if (permitting.nonEmpty()) { + print(" permits "); + print(permitting, ", "); + } + println(" {"); indent++; printClassMembers(tree.defs, isEnum, isInterface); @@ -1016,6 +1022,8 @@ public class PrettyPrinter extends JCTree.Visitor { if ((v & TRANSIENT) != 0) print("transient "); if ((v & NATIVE) != 0) print("native "); if ((v & ABSTRACT) != 0) print("abstract "); + if ((v & SEALED) != 0) print("sealed "); + if ((v & NON_SEALED) != 0) print("non-sealed "); if ((v & STRICTFP) != 0) print("strictfp "); if ((v & DEFAULT) != 0 && (v & INTERFACE) == 0) print("default "); } @@ -1324,13 +1332,16 @@ public class PrettyPrinter extends JCTree.Visitor { @Override public void visitCase(JCCase tree) { // Starting with JDK12, switches allow multiple expressions per case, and can take the form of an expression (preview feature). - List<JCExpression> pats = readObject(tree, "pats", null); // JDK 12+ + List<JCTree> pats = readObject(tree, "labels", null); // JDK 17+ + if (pats == null) { + pats = readObject(tree, "pats", null); // JDK 12-17 + } if (pats == null) { - JCExpression pat = readObject(tree, "pat", null); // JDK -11 - pats = pat == null ? List.<JCExpression>nil() : List.of(pat); + JCTree pat = readObject(tree, "pat", null); // JDK -11 + pats = pat == null ? List.<JCTree>nil() : List.of(pat); } - if (pats.isEmpty()) { + if (pats.isEmpty() || pats.size() == 1 && pats.head.getClass().getName().endsWith("$JCDefaultCaseLabel")) { aPrint("default"); } else { aPrint("case "); @@ -1421,6 +1432,22 @@ public class PrettyPrinter extends JCTree.Visitor { print((Name) readObject(var, "name", null)); } + void printDefaultCase(JCTree tree) { + print("default"); + } + + void printGuardPattern(JCTree tree) { + print((JCTree) readObject(tree, "patt", null)); + print(" && "); + print((JCExpression) readObject(tree, "expr", null)); + } + + void printParenthesizedPattern(JCTree tree) { + print("("); + print((JCTree) readObject(tree, "pattern", null)); + print(")"); + } + @Override public void visitTry(JCTry tree) { aPrint("try "); List<?> resources = readObject(tree, "resources", List.nil()); @@ -1639,6 +1666,12 @@ public class PrettyPrinter extends JCTree.Visitor { printYieldExpression(tree); } else if (className.endsWith("$JCBindingPattern")) { // Introduced as preview in JDK14 printBindingPattern(tree); + } else if (className.endsWith("$JCDefaultCaseLabel")) { // Introduced in JDK17 + printDefaultCase(tree); + } else if (className.endsWith("$JCGuardPattern")) { // Introduced in JDK17 + printGuardPattern(tree); + } else if (className.endsWith("$JCParenthesizedPattern")) { // Introduced in JDK17 + printParenthesizedPattern(tree); } 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 0a11cd7a..06e10960 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -87,14 +87,14 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchHideGeneratedNodes(sm); patchPostCompileHookEclipse(sm); patchFixSourceTypeConverter(sm); - patchDisableLombokForCodeCleanup(sm); patchListRewriteHandleGeneratedMethods(sm); patchSyntaxAndOccurrencesHighlighting(sm); patchSortMembersOperation(sm); - patchExtractInterface(sm); + patchExtractInterfaceAndPullUp(sm); patchAboutDialog(sm); patchEclipseDebugPatches(sm); patchJavadoc(sm); + patchASTConverterLiterals(sm); patchPostCompileHookEcj(sm); @@ -134,7 +134,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .transplant().build()); } - private static void patchExtractInterface(ScriptManager sm) { + private static void patchExtractInterfaceAndPullUp(ScriptManager sm) { /* Fix sourceEnding for generated nodes to avoid null pointer */ sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.compiler.SourceElementNotifier", "notifySourceElementRequestor", "void", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "org.eclipse.jdt.internal.compiler.ast.ImportReference")) @@ -156,10 +156,31 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .requestExtra(StackRequest.THIS, StackRequest.PARAM4) .transplant().build()); - /* get real generated node in stead of a random one generated by the annotation */ + /* Get real node source instead of the annotation */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor", "createPlaceholderForSingleVariableDeclaration", "org.eclipse.jdt.core.dom.SingleVariableDeclaration", + "org.eclipse.jdt.core.dom.SingleVariableDeclaration", + "org.eclipse.jdt.core.ICompilationUnit", + "org.eclipse.jdt.core.dom.rewrite.ASTRewrite" + )) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor", "createPlaceholderForType", "org.eclipse.jdt.core.dom.Type", + "org.eclipse.jdt.core.dom.Type", + "org.eclipse.jdt.core.ICompilationUnit", + "org.eclipse.jdt.core.dom.rewrite.ASTRewrite" + )) + .methodToWrap(new Hook("org.eclipse.jdt.core.IBuffer", "getText", "java.lang.String", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealNodeSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.dom.ASTNode")) + .requestExtra(StackRequest.PARAM1) + .transplant() + .build()); + + /* Get real generated node instead of a random one generated by the annotation */ sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMemberDeclarations")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMethodComments")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "createAbstractMethod")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "addMethodStubForAbstractMethod")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "createChangeManager")) .methodToReplace(new Hook("org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil", "getMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) .replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) .transplant().build()); @@ -177,6 +198,29 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .request(StackRequest.PARAM2) .transplant().build()); + + /* Do not add a modifier to the generating annotation during pull up + * + * Example: Pull up a protected method (canEqual()/@EqualsAndHashCode) + */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor$IncomingMemberVisibilityAdjustment", "rewriteVisibility")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "skipRewriteVisibility", "boolean", "org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor$IncomingMemberVisibilityAdjustment")) + .request(StackRequest.THIS) + .transplant() + .build()); + + /* + * ImportRemover sometimes removes lombok imports if a generated method/type gets changed. Skipping all generated nodes fixes this behavior. + * + * Example: Create a class (Use.java) that uses a generated method (Test t; t.toString();) and pull up this generated method. + */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover", "registerRemovedNode", "void", "org.eclipse.jdt.core.dom.ASTNode")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) + .request(StackRequest.PARAM1) + .transplant() + .build()); } private static void patchAboutDialog(ScriptManager sm) { @@ -200,20 +244,13 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .target(new MethodTarget("org.eclipse.jdt.internal.ui.search.OccurrencesFinder", "addUsage")) .target(new MethodTarget("org.eclipse.jdt.internal.ui.search.OccurrencesFinder", "addWrite")) .target(new MethodTarget("org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingReconciler$PositionCollector", "visit", "boolean", "org.eclipse.jdt.core.dom.SimpleName")) + .target(new MethodTarget("org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingReconciler$PositionCollector", "visitLiteral", "boolean", "org.eclipse.jdt.core.dom.Expression")) .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .valueMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "returnFalse", "boolean", "java.lang.Object")) .request(StackRequest.PARAM1) .build()); } - private static void patchDisableLombokForCodeCleanup(ScriptManager sm) { - sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() - .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTNode", "accept", "void", "org.eclipse.jdt.core.dom.ASTVisitor")) - .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isRefactoringVisitorAndGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.dom.ASTVisitor")) - .request(StackRequest.THIS, StackRequest.PARAM1) - .build()); - } - private static void patchListRewriteHandleGeneratedMethods(ScriptManager sm) { sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer$ListRewriter", "rewriteList")) @@ -308,6 +345,12 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { "org.eclipse.jdt.core.dom.SimpleName[]")) .request(StackRequest.RETURN_VALUE).build()); + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTNode", "accept", "void", "org.eclipse.jdt.core.dom.ASTVisitor")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isBlockedVisitorAndGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.core.dom.ASTVisitor")) + .request(StackRequest.THIS, StackRequest.PARAM1) + .build()); + patchRefactorScripts(sm); patchFormatters(sm); } @@ -528,6 +571,13 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.Block", "<init>", "void", "org.eclipse.jdt.core.dom.AST")) + .requestExtra(StackRequest.PARAM2) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void", + "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .transplant().build()); sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertType", "org.eclipse.jdt.core.dom.Type", "org.eclipse.jdt.internal.compiler.ast.TypeReference")) @@ -766,6 +816,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { sm.addScript(ScriptBuilder.replaceMethodCall() .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG)) + .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG, "boolean")) .methodToReplace(new Hook(EXPRESSION_SIG, "resolveType", TYPEBINDING_SIG, BLOCKSCOPE_SIG)) .requestExtra(StackRequest.THIS) .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Val", "skipResolveInitializerIfAlreadyCalled2", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG, LOCALDECLARATION_SIG)) @@ -895,6 +946,14 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .requestExtra(StackRequest.PARAM1) .build()); + /* This is a copy for the language server implementation that also supports markdown */ + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2", "getHTMLContent", "java.lang.String", "org.eclipse.jdt.core.IJavaElement", "boolean")) + .methodToWrap(new Hook("org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2", "getHTMLContentFromSource", "java.lang.String", "org.eclipse.jdt.core.IJavaElement")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Javadoc", "getHTMLContentFromSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.IJavaElement")) + .requestExtra(StackRequest.PARAM1) + .build()); + /* This is an older version that uses IMember instead of IJavaElement */ 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.IMember", "boolean")) @@ -919,4 +978,22 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .build()); } + private static void patchASTConverterLiterals(ScriptManager sm) { + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.Expression", "org.eclipse.jdt.internal.compiler.ast.StringLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.Expression", "org.eclipse.jdt.internal.compiler.ast.TextBlock")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.CharacterLiteral", "org.eclipse.jdt.internal.compiler.ast.CharLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.DoubleLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.FloatLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.LongLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.LongLiteralMinValue")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.IntLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.IntLiteralMinValue")) + .methodToWrap(new Hook("java.lang.String", "<init>", "void", "char[]", "int", "int")) + .requestExtra(StackRequest.PARAM1) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealNodeSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .transplant() + .build()); + } + } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java index 5b34917e..673c30fd 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2020-2021 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 @@ -103,8 +103,9 @@ public class PatchJavadoc { private static class Reflection { private static final Method javadoc2HTML; private static final Method oldJavadoc2HTML; + private static final Method lsJavadoc2HTML; static { - Method a = null, b = null; + Method a = null, b = null, c = null; try { a = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, IJavaElement.class, String.class); @@ -112,9 +113,13 @@ public class PatchJavadoc { try { b = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, String.class); } catch (Throwable t) {} + try { + c = Permit.getMethod(Class.forName("org.eclipse.jdt.ls.core.internal.javadoc.JavadocContentAccess2"), "javadoc2HTML", IMember.class, IJavaElement.class, String.class); + } catch (Throwable t) {} javadoc2HTML = a; oldJavadoc2HTML = b; + lsJavadoc2HTML = c; } private static String javadoc2HTML(IMember member, IJavaElement element, String rawJavadoc) { @@ -125,6 +130,13 @@ public class PatchJavadoc { return null; } } + if (lsJavadoc2HTML != null) { + try { + return (String) lsJavadoc2HTML.invoke(null, member, element, rawJavadoc); + } catch (Throwable t) { + return null; + } + } if (oldJavadoc2HTML != null) { try { return (String) oldJavadoc2HTML.invoke(null, member, rawJavadoc); diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 774e5b40..e758979d 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -35,13 +35,11 @@ import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression; import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; -import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; @@ -59,8 +57,8 @@ import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import java.lang.reflect.Field; import static lombok.Lombok.sneakyThrow; -import static lombok.eclipse.Eclipse.poss; -import static lombok.eclipse.handlers.EclipseHandlerUtil.makeType; +import static lombok.eclipse.Eclipse.*; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import static org.eclipse.jdt.core.compiler.CategorizedProblem.CAT_TYPE; public class PatchVal { @@ -237,13 +235,19 @@ public class PatchVal { TypeReference replacement = null; + // Java 10+: Lombok uses the native 'var' support and transforms 'val' to 'final var'. + if (hasNativeVarSupport(scope) && val) { + replacement = new SingleTypeReference("var".toCharArray(), pos(local.type)); + local.initialization = init; + init = null; + } + if (init != null) { if (init.getClass().getName().equals("org.eclipse.jdt.internal.compiler.ast.LambdaExpression")) { return false; } TypeBinding resolved = null; - Constant oldConstant = init.constant; try { resolved = decomponent ? getForEachComponentType(init, scope) : resolveForExpression(init, scope); } catch (NullPointerException e) { @@ -253,6 +257,46 @@ public class PatchVal { // just go with 'Object' and let the IDE print the appropriate errors. resolved = null; } + + if (resolved == null) { + if (init instanceof ConditionalExpression) { + ConditionalExpression cexp = (ConditionalExpression) init; + Expression ifTrue = cexp.valueIfTrue; + Expression ifFalse = cexp.valueIfFalse; + TypeBinding ifTrueResolvedType = ifTrue.resolvedType; + CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult; + CategorizedProblem[] problems = compilationResult.problems; + CategorizedProblem lastProblem = problems[compilationResult.problemCount - 1]; + if (ifTrueResolvedType != null && ifFalse.resolvedType == null && lastProblem.getCategoryID() == CAT_TYPE) { + int problemCount = compilationResult.problemCount; + for (int i = 0; i < problemCount; ++i) { + if (problems[i] == lastProblem) { + problems[i] = null; + if (i + 1 < problemCount) { + System.arraycopy(problems, i + 1, problems, i, problemCount - i + 1); + } + break; + } + } + compilationResult.removeProblem(lastProblem); + if (!compilationResult.hasErrors()) { + clearIgnoreFurtherInvestigationField(scope.referenceContext()); + setValue(getField(CompilationResult.class, "hasMandatoryErrors"), compilationResult, false); + } + + if (ifFalse instanceof FunctionalExpression) { + FunctionalExpression functionalExpression = (FunctionalExpression) ifFalse; + functionalExpression.setExpectedType(ifTrueResolvedType); + } + if (ifFalse.resolvedType == null) { + resolveForExpression(ifFalse, scope); + } + + resolved = ifTrueResolvedType; + } + } + } + if (resolved != null) { try { replacement = makeType(resolved, local.type, false); @@ -260,10 +304,6 @@ public class PatchVal { } catch (Exception e) { // Some type thing failed. } - } else { - if (init instanceof MessageSend && ((MessageSend) init).actualReceiverType == null) { - init.constant = oldConstant; - } } } @@ -281,6 +321,14 @@ public class PatchVal { return is(local.type, scope, "lombok.val"); } + private static boolean hasNativeVarSupport(Scope scope) { + long sl = scope.problemReporter().options.sourceLevel >> 16; + long cl = scope.problemReporter().options.complianceLevel >> 16; + if (sl == 0) sl = cl; + if (cl == 0) cl = sl; + return Math.min((int)(sl - 44), (int)(cl - 44)) >= 10; + } + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { if (forEach.elementVariable == null) return false; @@ -288,6 +336,8 @@ public class PatchVal { boolean var = isVar(forEach.elementVariable, scope); if (!(val || var)) return false; + if (hasNativeVarSupport(scope)) return false; + TypeBinding component = getForEachComponentType(forEach.collection, scope); if (component == null) return false; TypeReference replacement = makeType(component, forEach.elementVariable.type, false); @@ -353,43 +403,7 @@ public class PatchVal { // Known cause of issues; for example: val e = mth("X"), where mth takes 2 arguments. return null; } catch (AbortCompilation e) { - if (collection instanceof ConditionalExpression) { - ConditionalExpression cexp = (ConditionalExpression) collection; - Expression ifTrue = cexp.valueIfTrue; - Expression ifFalse = cexp.valueIfFalse; - TypeBinding ifTrueResolvedType = ifTrue.resolvedType; - CategorizedProblem problem = e.problem; - if (ifTrueResolvedType != null && ifFalse.resolvedType == null && problem.getCategoryID() == CAT_TYPE) { - CompilationResult compilationResult = e.compilationResult; - CategorizedProblem[] problems = compilationResult.problems; - int problemCount = compilationResult.problemCount; - for (int i = 0; i < problemCount; ++i) { - if (problems[i] == problem) { - problems[i] = null; - if (i + 1 < problemCount) { - System.arraycopy(problems, i + 1, problems, i, problemCount - i + 1); - } - break; - } - } - compilationResult.removeProblem(problem); - if (!compilationResult.hasErrors()) { - clearIgnoreFurtherInvestigationField(scope.referenceContext()); - setValue(getField(CompilationResult.class, "hasMandatoryErrors"), compilationResult, false); - } - - if (ifFalse instanceof FunctionalExpression) { - FunctionalExpression functionalExpression = (FunctionalExpression) ifFalse; - functionalExpression.setExpectedType(ifTrueResolvedType); - } - if (ifFalse.resolvedType == null) { - ifFalse.resolve(scope); - } - - return ifTrueResolvedType; - } - } - throw e; + return null; } } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index bee30922..63bb3747 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; +import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment; import static lombok.eclipse.EcjAugments.ASTNode_generatedBy; @@ -413,25 +414,27 @@ final class PatchFixesHider { } return result; } - - public static boolean isRefactoringVisitorAndGenerated(org.eclipse.jdt.core.dom.ASTNode node, org.eclipse.jdt.core.dom.ASTVisitor visitor) { - if (visitor == null) return false; - - String className = visitor.getClass().getName(); - if (!(className.startsWith("org.eclipse.jdt.internal.corext.fix") || className.startsWith("org.eclipse.jdt.internal.ui.fix"))) return false; - + + public static boolean isGenerated(org.eclipse.jdt.core.IMember member) { boolean result = false; try { - result = ((Boolean)node.getClass().getField("$isGenerated").get(node)).booleanValue(); - if (!result && node.getParent() != null && node.getParent() instanceof org.eclipse.jdt.core.dom.QualifiedName) { - result = isGenerated(node.getParent()); - } - } catch (Exception e) { + result = member.getNameRange().getLength() <= 0 || member.getNameRange().equals(member.getSourceRange()); + } catch (JavaModelException e) { // better to assume it isn't generated } return result; } + public static boolean isBlockedVisitorAndGenerated(org.eclipse.jdt.core.dom.ASTNode node, org.eclipse.jdt.core.dom.ASTVisitor visitor) { + if (visitor == null) return false; + + String className = visitor.getClass().getName(); + if (!(className.startsWith("org.eclipse.jdt.internal.corext.fix") || className.startsWith("org.eclipse.jdt.internal.ui.fix") || className.startsWith("org.eclipse.jdt.ls.core.internal.semantictokens.SemanticTokensVisitor"))) return false; + if (className.equals("org.eclipse.jdt.internal.corext.fix.VariableDeclarationFixCore$WrittenNamesFinder")) return false; + + return isGenerated(node); + } + public static boolean isListRewriteOnGeneratedNode(org.eclipse.jdt.core.dom.rewrite.ListRewrite rewrite) { return isGenerated(rewrite.getParent()); } @@ -473,8 +476,10 @@ final class PatchFixesHider { StringBuilder signature = new StringBuilder(); addAnnotations(annotations, signature); - if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); - if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); + try { + if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); + if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); + } catch (Throwable t) { } signature .append(declaration.getReturnType2().toString()) @@ -520,7 +525,7 @@ final class PatchFixesHider { for (Object value : normalAnn.values()) values.add(value.toString()); } - signature.append("@").append(annotation.resolveTypeBinding().getQualifiedName()); + signature.append("@").append(annotation.getTypeName().getFullyQualifiedName()); if (!values.isEmpty()) { signature.append("("); boolean first = true; @@ -696,7 +701,7 @@ final class PatchFixesHider { public static IMethod[] removeGeneratedMethods(IMethod[] methods) throws Exception { List<IMethod> result = new ArrayList<IMethod>(); for (IMethod m : methods) { - if (m.getNameRange().getLength() > 0 && !m.getNameRange().equals(m.getSourceRange())) result.add(m); + if (!isGenerated(m)) result.add(m); } return result.size() == methods.length ? methods : result.toArray(new IMethod[0]); } @@ -799,5 +804,21 @@ final class PatchFixesHider { return replace; } + + public static String getRealNodeSource(String original, org.eclipse.jdt.internal.compiler.ast.ASTNode node) { + if (!isGenerated(node)) return original; + + return node.toString(); + } + + public static java.lang.String getRealNodeSource(java.lang.String original, org.eclipse.jdt.core.dom.ASTNode node) throws Exception { + if (!isGenerated(node)) return original; + + return node.toString(); + } + + public static boolean skipRewriteVisibility(IncomingMemberVisibilityAdjustment adjustment) { + return isGenerated(adjustment.getMember()); + } } } diff --git a/src/installer/lombok/installer/IdeLocation.java b/src/installer/lombok/installer/IdeLocation.java index 6b9a94c6..7cba1e2a 100644 --- a/src/installer/lombok/installer/IdeLocation.java +++ b/src/installer/lombok/installer/IdeLocation.java @@ -64,16 +64,4 @@ public abstract class IdeLocation { return x == null ? p.getPath() : x; } } - - private static final String LEGAL_PATH_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/"; - private static final String LEGAL_PATH_CHARS_WINDOWS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,/;'[]{}!@#$^&()-_+= :\\"; - public static String escapePath(String path) { - StringBuilder out = new StringBuilder(); - String legalChars = OsUtils.getOS() == OsUtils.OS.UNIX ? LEGAL_PATH_CHARS : LEGAL_PATH_CHARS_WINDOWS; - for (char c : path.toCharArray()) { - if (legalChars.indexOf(c) == -1) out.append('\\'); - out.append(c); - } - return out.toString(); - } } diff --git a/src/installer/lombok/installer/eclipse/EclipseProductLocation.java b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java index 73f98a35..4cfd07f5 100644 --- a/src/installer/lombok/installer/eclipse/EclipseProductLocation.java +++ b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java @@ -347,8 +347,10 @@ public final class EclipseProductLocation extends IdeLocation { pathPrefix = pathToLombokJarPrefix; } + // NB: You may be tempted to escape this, but don't; there is no possibility to escape this, but + // eclipse/java reads the string following the colon in 'raw' fashion. Spaces, colons - all works fine. newContents.append(String.format( - "-javaagent:%s", escapePath(pathPrefix + "lombok.jar"))).append(OS_NEWLINE); + "-javaagent:%s", pathPrefix + "lombok.jar")).append(OS_NEWLINE); FileOutputStream fos = new FileOutputStream(eclipseIniPath); try { diff --git a/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java index 9bd3ae94..365bf7fb 100644 --- a/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java +++ b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java @@ -35,6 +35,7 @@ import lombok.installer.OsUtils; public class StandardProductDescriptor implements EclipseProductDescriptor { private static final String USER_HOME = System.getProperty("user.home", "."); + private static final String[] BASE_WINDOWS_ROOTS = {"\\", "\\Program Files", "\\Program Files (x86)", "\\ProgramData\\Chocolatey\\lib"}; private static final String[] WINDOWS_ROOTS = windowsRoots(); private static final String[] MAC_ROOTS = {"/Applications", USER_HOME}; private static final String[] UNIX_ROOTS = {USER_HOME}; @@ -159,8 +160,11 @@ public class StandardProductDescriptor implements EclipseProductDescriptor { private static String[] windowsRoots() { String localAppData = windowsLocalAppData(); - if (localAppData == null) return new String[] {"\\", "\\Program Files", "\\Program Files (x86)", USER_HOME}; - return new String[] {"\\", "\\Program Files", "\\Program Files (x86)", USER_HOME, localAppData}; + String[] out = new String[BASE_WINDOWS_ROOTS.length + (localAppData == null ? 1 : 2)]; + System.arraycopy(BASE_WINDOWS_ROOTS, 0, out, 0, BASE_WINDOWS_ROOTS.length); + out[BASE_WINDOWS_ROOTS.length] = USER_HOME; + if (localAppData != null) out[BASE_WINDOWS_ROOTS.length + 1] = localAppData; + return out; } private static String windowsLocalAppData() { diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index 8af481b9..0f42ddc6 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -224,8 +224,11 @@ public class Eclipse { int highestVersionSoFar = 0; for (Field f : ClassFileConstants.class.getDeclaredFields()) { try { - if (f.getName().startsWith("JDK1_")) { - int thisVersion = Integer.parseInt(f.getName().substring("JDK1_".length())); + if (f.getName().startsWith("JDK")) { + String versionString = f.getName().substring("JDK".length()); + if (versionString.startsWith("1_")) versionString = versionString.substring("1_".length()); + + int thisVersion = Integer.parseInt(versionString); if (thisVersion > highestVersionSoFar) { highestVersionSoFar = thisVersion; latestEcjCompilerVersionConstantCached = (Long) f.get(null); diff --git a/src/utils/lombok/javac/Java14Flags.java b/src/utils/lombok/javac/Java14Flags.java deleted file mode 100644 index 0d565dca..00000000 --- a/src/utils/lombok/javac/Java14Flags.java +++ /dev/null @@ -1,26 +0,0 @@ -package lombok.javac; - -public class Java14Flags { - private Java14Flags() { } - - /** - * Flag to indicate that a class is a record. The flag is also used to mark fields that are - * part of the state vector of a record and to mark the canonical constructor - */ - public static final long RECORD = 1L<<61; // ClassSymbols, MethodSymbols and VarSymbols - - /** - * Flag to mark a record constructor as a compact one - */ - public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51; // MethodSymbols only - - /** - * Flag to mark a record field that was not initialized in the compact constructor - */ - public static final long UNINITIALIZED_FIELD= 1L<<51; // VarSymbols only - - /** Flag is set for compiler-generated record members, it could be appplied to - * accessors and fields - */ - public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols -} diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index d9fcc4f2..3fa0fbb5 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -80,6 +80,8 @@ public class Javac { public static final long COMPACT_RECORD_CONSTRUCTOR = 1L << 51; // MethodSymbols (the 'implicit' many-args constructor that records have) public static final long UNINITIALIZED_FIELD = 1L << 51; // VarSymbols (To identify fields that the compact record constructor won't initialize) public static final long GENERATED_MEMBER = 1L << 24; // MethodSymbols, VarSymbols (marks methods and the constructor generated in records) + public static final long SEALED = 1L << 62; // ClassSymbols (Flag to indicate sealed class/interface declaration) + public static final long NON_SEALED = 1L << 63; // ClassSymbols (Flag to indicate that the class/interface was declared with the non-sealed modifier) /** * Returns the version of this java compiler, i.e. the JDK that it shipped in. For example, for javac v1.7, this returns {@code 7}. diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java index 30d71606..d369b4e4 100644 --- a/src/utils/lombok/javac/JavacTreeMaker.java +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -607,7 +607,19 @@ public class JavacTreeMaker { public JCCase Case(JCExpression pat, List<JCStatement> stats) { if (tryResolve(Case11)) return invoke(Case11, pat, stats); - return invoke(Case12.Case12, Case12.CASE_KIND_STATEMENT, pat == null ? com.sun.tools.javac.util.List.nil() : com.sun.tools.javac.util.List.of(pat), stats, null); + List<JCTree> labels; + if (pat == null) { + labels = tryResolve(DefaultCaseLabel) ? List.of(DefaultCaseLabel()) : List.<JCTree>nil(); + } else { + labels = List.<JCTree>of(pat); + } + return invoke(Case12.Case12, Case12.CASE_KIND_STATEMENT, labels, stats, null); + } + + //javac versions: 17 + private static final MethodId<JCTree> DefaultCaseLabel = MethodId("DefaultCaseLabel", JCTree.class); + public JCTree DefaultCaseLabel() { + return invoke(DefaultCaseLabel); } //javac versions: 6-8 diff --git a/src/utils/lombok/javac/TreeMirrorMaker.java b/src/utils/lombok/javac/TreeMirrorMaker.java index a67a4ec1..44e26ab6 100644 --- a/src/utils/lombok/javac/TreeMirrorMaker.java +++ b/src/utils/lombok/javac/TreeMirrorMaker.java @@ -32,8 +32,10 @@ import lombok.javac.JavacTreeMaker.TypeTag; import com.sun.source.tree.LabeledStatementTree; import com.sun.source.tree.VariableTree; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeCopier; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; @@ -109,6 +111,21 @@ public class TreeMirrorMaker extends TreeCopier<Void> { if (wipeSymAndType) { copy.sym = null; copy.type = null; + } else { + if (original.vartype != null) { + copy.vartype.type = original.vartype.type; + original.vartype.accept(new TreeScanner() { + @Override public void scan(JCTree tree) { + super.scan(tree); + originalToCopy.get(tree).type = tree.type; + } + + @Override public void visitSelect(JCFieldAccess tree) { + super.visitSelect(tree); + ((JCFieldAccess) originalToCopy.get(tree)).sym = tree.sym; + } + }); + } } } diff --git a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java index f29f501b..e625cd8d 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java +++ b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java @@ -21,6 +21,7 @@ */ package lombok.javac.java8; +import java.nio.Buffer; import java.nio.CharBuffer; import com.sun.tools.javac.parser.Scanner; @@ -79,7 +80,7 @@ public class CommentCollectingScannerFactory extends ScannerFactory { int limit; if (input instanceof CharBuffer && ((CharBuffer) input).hasArray()) { CharBuffer cb = (CharBuffer) input; - cb.compact().flip(); + ((Buffer)cb.compact()).flip(); array = cb.array(); limit = cb.limit(); } else { diff --git a/test/core/src/lombok/DirectoryRunner.java b/test/core/src/lombok/DirectoryRunner.java index b041c42e..53347e24 100644 --- a/test/core/src/lombok/DirectoryRunner.java +++ b/test/core/src/lombok/DirectoryRunner.java @@ -55,7 +55,8 @@ public class DirectoryRunner extends Runner { }, ECJ { @Override public int getVersion() { - return Eclipse.getEcjCompilerVersion(); + String javaVersionString = System.getProperty("compiler.compliance.level"); + return javaVersionString != null ? Integer.parseInt(javaVersionString) : Eclipse.getEcjCompilerVersion(); } }; diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index 0326dee9..27ffc31a 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -161,6 +161,7 @@ public class LombokTestSource { private static final Pattern UNCHANGED_PATTERN = Pattern.compile("^\\s*unchanged\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); 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 LombokTestSource(File file, String content, List<CompilerMessageMatcher> messages, List<String> directives) { this.file = file; @@ -200,6 +201,9 @@ public class LombokTestSource { skipIdempotent = true; continue; } + if (ISSUE_REF_PATTERN.matcher(directive).matches()) { + continue; + } if (lc.startsWith("platform ")) { String platformDesc = lc.substring("platform ".length()); diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java index 23a42c67..e4eb1a30 100644 --- a/test/core/src/lombok/RunTestsViaDelombok.java +++ b/test/core/src/lombok/RunTestsViaDelombok.java @@ -42,7 +42,6 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; import com.sun.source.util.TreePath; @@ -211,8 +210,8 @@ public class RunTestsViaDelombok extends AbstractRunTests { } @Override public void visitVarDef(JCVariableDecl tree) { - // Skip non-field variables - if (!(parent instanceof JCClassDecl)) return; + // Skip local variables + if (!(parent instanceof JCClassDecl || parent instanceof JCMethodDecl)) return; validateSymbol(tree, tree.sym); super.visitVarDef(tree); @@ -222,8 +221,8 @@ public class RunTestsViaDelombok extends AbstractRunTests { if (sym == null) { fail("Missing symbol for " + tree); } - // Skip top level classes - if (sym.owner.getKind() == ElementKind.PACKAGE) return; + // Only classes have enclosed elements, skip everything else + if (!sym.owner.getKind().isClass()) return; if (!sym.owner.getEnclosedElements().contains(sym)) { fail(tree + " not added to parent"); diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index afba8c7f..6137de49 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -64,9 +64,22 @@ import org.osgi.framework.BundleContext; public class RunTestsViaEcj extends AbstractRunTests { protected CompilerOptions ecjCompilerOptions() { CompilerOptions options = new CompilerOptions(); - options.complianceLevel = Eclipse.getLatestEcjCompilerVersionConstant(); - options.sourceLevel = Eclipse.getLatestEcjCompilerVersionConstant(); - options.targetJDK = Eclipse.getLatestEcjCompilerVersionConstant(); + Map<String, String> warnings = new HashMap<String, String>(); + + 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; + } 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"); + } + options.complianceLevel = ecjCompilerVersionConstant; + options.sourceLevel = ecjCompilerVersionConstant; + options.targetJDK = ecjCompilerVersionConstant; options.docCommentSupport = false; options.parseLiteralExpressionsAsConstants = true; options.inlineJsrBytecode = true; @@ -78,17 +91,14 @@ public class RunTestsViaEcj extends AbstractRunTests { options.reportUnusedParameterWhenOverridingConcrete = false; options.reportDeadCodeInTrivialIfStatement = false; options.generateClassFiles = false; - Map<String, String> warnings = new HashMap<String, String>(); warnings.put(CompilerOptions.OPTION_ReportUnusedLocal, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedLabel, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedImport, "ignore"); warnings.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, "ignore"); warnings.put(CompilerOptions.OPTION_ReportIndirectStaticAccess, "warning"); warnings.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, "warning"); - warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled"); warnings.put("org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures", "ignore"); - int ecjVersion = Eclipse.getEcjCompilerVersion(); - warnings.put(CompilerOptions.OPTION_Source, (ecjVersion < 9 ? "1." : "") + ecjVersion); + warnings.put(CompilerOptions.OPTION_Source, (ecjCompilerVersion < 9 ? "1." : "") + ecjCompilerVersion); options.set(warnings); return options; } @@ -96,7 +106,7 @@ public class RunTestsViaEcj extends AbstractRunTests { protected IErrorHandlingPolicy ecjErrorHandlingPolicy() { return new IErrorHandlingPolicy() { public boolean stopOnFirstError() { - return true; + return false; } public boolean proceedOnErrors() { diff --git a/test/pretty/resource/after/Sealed.java b/test/pretty/resource/after/Sealed.java new file mode 100644 index 00000000..15096034 --- /dev/null +++ b/test/pretty/resource/after/Sealed.java @@ -0,0 +1,16 @@ +public class Sealed { + public abstract sealed class Parent permits Child1, Child2 { + } + + public final class Child1 extends Parent { + } + + public abstract non-sealed class Child2 extends Parent { + } + + public sealed interface SealedInterface permits ChildInterface1 { + } + + public non-sealed interface ChildInterface1 extends SealedInterface { + } +}
\ No newline at end of file diff --git a/test/pretty/resource/after/Switch17.java b/test/pretty/resource/after/Switch17.java new file mode 100644 index 00000000..038f2cd9 --- /dev/null +++ b/test/pretty/resource/after/Switch17.java @@ -0,0 +1,31 @@ +public class Switch17 { + String switchPatternMatching(Object o) { + return switch (o) { + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format("double %f", d); + case String s -> String.format("String %s", s); + default -> o.toString(); + }; + } + + String switchNull(Object o) { + return switch (o) { + case null, default -> "?"; + }; + } + + String switchGuardPattern(Object o) { + return switch (o) { + case String s && s.length() > 1 -> s; + default -> o.toString(); + }; + } + + String switchParenthesizedPattern(Object o) { + return switch (o) { + case (String s) -> s; + default -> o.toString(); + }; + } +}
\ No newline at end of file diff --git a/test/pretty/resource/after/ThisParameter.java b/test/pretty/resource/after/ThisParameter.java index 49452a59..c57916be 100644 --- a/test/pretty/resource/after/ThisParameter.java +++ b/test/pretty/resource/after/ThisParameter.java @@ -16,17 +16,17 @@ class ThisParameter { void runtimeTagged(@RuntimeTagged("runtime") ThisParameter this) { // no content } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.SOURCE) @interface SourceTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.CLASS) @interface ClassTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) @interface RuntimeTagged { String value(); diff --git a/test/pretty/resource/before/Sealed.java b/test/pretty/resource/before/Sealed.java new file mode 100644 index 00000000..46828627 --- /dev/null +++ b/test/pretty/resource/before/Sealed.java @@ -0,0 +1,17 @@ +// version 15: +public class Sealed { + public abstract sealed class Parent permits Child1, Child2 { + } + + public final class Child1 extends Parent { + } + + public abstract non-sealed class Child2 extends Parent { + } + + public sealed interface SealedInterface permits ChildInterface1 { + } + + public non-sealed interface ChildInterface1 extends SealedInterface { + } +}
\ No newline at end of file diff --git a/test/pretty/resource/before/Switch17.java b/test/pretty/resource/before/Switch17.java new file mode 100644 index 00000000..17754e82 --- /dev/null +++ b/test/pretty/resource/before/Switch17.java @@ -0,0 +1,32 @@ +// version 17: +public class Switch17 { + String switchPatternMatching(Object o) { + return switch (o) { + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format("double %f", d); + case String s -> String.format("String %s", s); + default -> o.toString(); + }; + } + + String switchNull(Object o) { + return switch (o) { + case null, default -> "?"; + }; + } + + String switchGuardPattern(Object o) { + return switch (o) { + case String s && s.length() > 1 -> s; + default -> o.toString(); + }; + } + + String switchParenthesizedPattern(Object o) { + return switch (o) { + case (String s) -> s; + default -> o.toString(); + }; + } +} diff --git a/test/pretty/resource/before/ThisParameter.java b/test/pretty/resource/before/ThisParameter.java index e37651cb..42e4237e 100644 --- a/test/pretty/resource/before/ThisParameter.java +++ b/test/pretty/resource/before/ThisParameter.java @@ -1,4 +1,4 @@ -// version 9: the 'this' param option exists in java8, but is bugged, in that annotations are not allowed on them, even without a @Target. The only purpose of the this param is annotations, so, boy, isn't that a punch in the face? +// version 8: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -22,19 +22,19 @@ class ThisParameter { // no content } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.SOURCE) @interface SourceTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.CLASS) @interface ClassTagged { String value(); } - @Target(ElementType.PARAMETER) + @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) @interface RuntimeTagged { String value(); diff --git a/test/pretty/resource/messages/DefaultMethod.java.messages b/test/pretty/resource/messages/DefaultMethod.java.messages new file mode 100644 index 00000000..766c3d8c --- /dev/null +++ b/test/pretty/resource/messages/DefaultMethod.java.messages @@ -0,0 +1 @@ +OPTIONAL 9 as of release 17, all floating-point expressions are evaluated strictly and 'strictfp' is not required
\ No newline at end of file diff --git a/test/pretty/resource/messages/ExoticJava.java.messages b/test/pretty/resource/messages/ExoticJava.java.messages new file mode 100644 index 00000000..68e8d281 --- /dev/null +++ b/test/pretty/resource/messages/ExoticJava.java.messages @@ -0,0 +1 @@ +OPTIONAL 16 as of release 17, all floating-point expressions are evaluated strictly and 'strictfp' is not required
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/AccessorsInAnonymousClass.java b/test/transform/resource/after-delombok/AccessorsInAnonymousClass.java new file mode 100644 index 00000000..27fab509 --- /dev/null +++ b/test/transform/resource/after-delombok/AccessorsInAnonymousClass.java @@ -0,0 +1,22 @@ +public class AccessorsInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public String string() { + return this.string; + } + + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public Inner string(final String string) { + this.string = string; + return this; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/BuilderInAnonymousClass.java b/test/transform/resource/after-delombok/BuilderInAnonymousClass.java new file mode 100644 index 00000000..4810a0a8 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderInAnonymousClass.java @@ -0,0 +1,8 @@ +public class BuilderInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/BuilderNestedInEnum.java b/test/transform/resource/after-delombok/BuilderNestedInEnum.java new file mode 100644 index 00000000..26dc2a06 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderNestedInEnum.java @@ -0,0 +1,70 @@ +class BuilderNestedInEnum { + public enum TestEnum { + FOO, BAR; + public static final class TestBuilder { + private final String field; + @java.lang.SuppressWarnings("all") + TestBuilder(final String field) { + this.field = field; + } + @java.lang.SuppressWarnings("all") + public static class TestBuilderBuilder { + @java.lang.SuppressWarnings("all") + private String field; + @java.lang.SuppressWarnings("all") + TestBuilderBuilder() { + } + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder field(final String field) { + this.field = field; + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderNestedInEnum.TestEnum.TestBuilder build() { + return new BuilderNestedInEnum.TestEnum.TestBuilder(this.field); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(field=" + this.field + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder builder() { + return new BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(); + } + @java.lang.SuppressWarnings("all") + public String getField() { + return this.field; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof BuilderNestedInEnum.TestEnum.TestBuilder)) return false; + final BuilderNestedInEnum.TestEnum.TestBuilder other = (BuilderNestedInEnum.TestEnum.TestBuilder) o; + final java.lang.Object this$field = this.getField(); + final java.lang.Object other$field = other.getField(); + if (this$field == null ? other$field != null : !this$field.equals(other$field)) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $field = this.getField(); + result = result * PRIME + ($field == null ? 43 : $field.hashCode()); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderNestedInEnum.TestEnum.TestBuilder(field=" + this.getField() + ")"; + } + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/BuilderWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/BuilderWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..4a21f2c3 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderWithJavaBeansSpecCapitalization.java @@ -0,0 +1,106 @@ +class BuilderWithJavaBeansSpecCapitalization { + java.util.List<String> a; + java.util.List<String> aField; + String bField; + @java.lang.SuppressWarnings("all") + BuilderWithJavaBeansSpecCapitalization(final java.util.List<String> a, final java.util.List<String> aField, final String bField) { + this.a = a; + this.aField = aField; + this.bField = bField; + } + @java.lang.SuppressWarnings("all") + public static class BuilderWithJavaBeansSpecCapitalizationBuilder { + @java.lang.SuppressWarnings("all") + private java.util.ArrayList<String> a; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList<String> aField; + @java.lang.SuppressWarnings("all") + private String bField; + @java.lang.SuppressWarnings("all") + BuilderWithJavaBeansSpecCapitalizationBuilder() { + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setZ(final String z) { + if (this.a == null) this.a = new java.util.ArrayList<String>(); + this.a.add(z); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setA(final java.util.Collection<? extends String> a) { + if (a == null) { + throw new java.lang.NullPointerException("a cannot be null"); + } + if (this.a == null) this.a = new java.util.ArrayList<String>(); + this.a.addAll(a); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearA() { + if (this.a != null) this.a.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setyField(final String yField) { + if (this.aField == null) this.aField = new java.util.ArrayList<String>(); + this.aField.add(yField); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setaField(final java.util.Collection<? extends String> aField) { + if (aField == null) { + throw new java.lang.NullPointerException("aField cannot be null"); + } + if (this.aField == null) this.aField = new java.util.ArrayList<String>(); + this.aField.addAll(aField); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearaField() { + if (this.aField != null) this.aField.clear(); + return this; + } + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setbField(final String bField) { + this.bField = bField; + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithJavaBeansSpecCapitalization build() { + java.util.List<String> a; + switch (this.a == null ? 0 : this.a.size()) { + case 0: + a = java.util.Collections.emptyList(); + break; + case 1: + a = java.util.Collections.singletonList(this.a.get(0)); + break; + default: + a = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(this.a)); + } + java.util.List<String> aField; + switch (this.aField == null ? 0 : this.aField.size()) { + case 0: + aField = java.util.Collections.emptyList(); + break; + case 1: + aField = java.util.Collections.singletonList(this.aField.get(0)); + break; + default: + aField = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(this.aField)); + } + return new BuilderWithJavaBeansSpecCapitalization(a, aField, this.bField); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(a=" + this.a + ", aField=" + this.aField + ", bField=" + this.bField + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder builder() { + return new BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java b/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java new file mode 100644 index 00000000..7483718f --- /dev/null +++ b/test/transform/resource/after-delombok/ConstructorsInAnonymousClass.java @@ -0,0 +1,34 @@ +//version 8: +import lombok.NonNull; + +public class ConstructorsInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + @NonNull + private String string2; + + @java.lang.SuppressWarnings("all") + public Inner(final String string, @NonNull final String string2) { + if (string2 == null) { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string = string; + this.string2 = string2; + } + + @java.lang.SuppressWarnings("all") + public Inner(@NonNull final String string2) { + if (string2 == null) { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string2 = string2; + } + + @java.lang.SuppressWarnings("all") + public Inner() { + } + } + }; +} diff --git a/test/transform/resource/after-delombok/DataInAnonymousClass.java b/test/transform/resource/after-delombok/DataInAnonymousClass.java new file mode 100644 index 00000000..788d7be5 --- /dev/null +++ b/test/transform/resource/after-delombok/DataInAnonymousClass.java @@ -0,0 +1,56 @@ +public class DataInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public Inner() { + } + + @java.lang.SuppressWarnings("all") + public String getString() { + return this.string; + } + + @java.lang.SuppressWarnings("all") + public void setString(final String string) { + this.string = string; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Inner)) return false; + final Inner other = (Inner) o; + if (!other.canEqual((java.lang.Object) this)) return false; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (this$string == null ? other$string != null : !this$string.equals(other$string)) return false; + return true; + } + + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof Inner; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = result * PRIME + ($string == null ? 43 : $string.hashCode()); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Inner(string=" + this.getString() + ")"; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeInAnonymousClass.java b/test/transform/resource/after-delombok/EqualsAndHashCodeInAnonymousClass.java new file mode 100644 index 00000000..6f0b5738 --- /dev/null +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeInAnonymousClass.java @@ -0,0 +1,36 @@ +public class EqualsAndHashCodeInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Inner)) return false; + final Inner other = (Inner) o; + if (!other.canEqual((java.lang.Object) this)) return false; + final java.lang.Object this$string = this.string; + final java.lang.Object other$string = other.string; + if (this$string == null ? other$string != null : !this$string.equals(other$string)) return false; + return true; + } + + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof Inner; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.string; + result = result * PRIME + ($string == null ? 43 : $string.hashCode()); + return result; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/FieldDefaultsViaConfigOnRecord.java b/test/transform/resource/after-delombok/FieldDefaultsViaConfigOnRecord.java new file mode 100644 index 00000000..1a2ce882 --- /dev/null +++ b/test/transform/resource/after-delombok/FieldDefaultsViaConfigOnRecord.java @@ -0,0 +1,3 @@ +// version 14: +public record FieldDefaultsViaConfigOnRecord(String a, String b) { +} diff --git a/test/transform/resource/after-delombok/FieldNameConstantsInAnonymousClass.java b/test/transform/resource/after-delombok/FieldNameConstantsInAnonymousClass.java new file mode 100644 index 00000000..1f7e7d7a --- /dev/null +++ b/test/transform/resource/after-delombok/FieldNameConstantsInAnonymousClass.java @@ -0,0 +1,8 @@ +public class FieldNameConstantsInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/GetterInAnonymousClass.java b/test/transform/resource/after-delombok/GetterInAnonymousClass.java new file mode 100644 index 00000000..3c990545 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterInAnonymousClass.java @@ -0,0 +1,13 @@ +public class GetterInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public String getString() { + return this.string; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java b/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java new file mode 100644 index 00000000..4476e463 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterLazyInAnonymousClass.java @@ -0,0 +1,24 @@ +public class GetterLazyInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private final java.util.concurrent.atomic.AtomicReference<java.lang.Object> string = new java.util.concurrent.atomic.AtomicReference<java.lang.Object>(); + + @java.lang.SuppressWarnings({"all", "unchecked"}) + public String getString() { + java.lang.Object value = this.string.get(); + if (value == null) { + synchronized (this.string) { + value = this.string.get(); + if (value == null) { + final String actualValue = "test"; + value = actualValue == null ? this.string : actualValue; + this.string.set(value); + } + } + } + return (String) (value == this.string ? null : value); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..51ccfe63 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,12 @@ +class GetterWithJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public int getA() { + return this.a; + } + @java.lang.SuppressWarnings("all") + public int getaField() { + return this.aField; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4jInAnonymousClass.java b/test/transform/resource/after-delombok/LoggerSlf4jInAnonymousClass.java new file mode 100644 index 00000000..1ec25d92 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jInAnonymousClass.java @@ -0,0 +1,7 @@ +public class LoggerSlf4jInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + } + }; +} diff --git a/test/transform/resource/after-delombok/SetterInAnonymousClass.java b/test/transform/resource/after-delombok/SetterInAnonymousClass.java new file mode 100644 index 00000000..ced2be52 --- /dev/null +++ b/test/transform/resource/after-delombok/SetterInAnonymousClass.java @@ -0,0 +1,13 @@ +public class SetterInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.SuppressWarnings("all") + public void setString(final String string) { + this.string = string; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..de68ee60 --- /dev/null +++ b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,12 @@ +class SetterWithJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public void setA(final int a) { + this.a = a; + } + @java.lang.SuppressWarnings("all") + public void setaField(final int aField) { + this.aField = aField; + } +} diff --git a/test/transform/resource/after-delombok/SuperBuilderInAnonymousClass.java b/test/transform/resource/after-delombok/SuperBuilderInAnonymousClass.java new file mode 100644 index 00000000..cc654919 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderInAnonymousClass.java @@ -0,0 +1,12 @@ +public class SuperBuilderInAnonymousClass { + Object annonymous = new Object() { + + class InnerParent { + private String string; + } + + class InnerChild { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/SynchronizedInAnonymousClass.java b/test/transform/resource/after-delombok/SynchronizedInAnonymousClass.java new file mode 100644 index 00000000..904487a3 --- /dev/null +++ b/test/transform/resource/after-delombok/SynchronizedInAnonymousClass.java @@ -0,0 +1,15 @@ +public class SynchronizedInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + @java.lang.SuppressWarnings("all") + private final java.lang.Object $lock = new java.lang.Object[0]; + + public void foo() { + synchronized (this.$lock) { + String foo = "bar"; + } + } + } + }; +} diff --git a/test/transform/resource/after-delombok/ToStringInAnonymousClass.java b/test/transform/resource/after-delombok/ToStringInAnonymousClass.java new file mode 100644 index 00000000..aa3651bb --- /dev/null +++ b/test/transform/resource/after-delombok/ToStringInAnonymousClass.java @@ -0,0 +1,14 @@ +public class ToStringInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Inner(string=" + this.string + ")"; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/UtilityClassInAnonymousClass.java b/test/transform/resource/after-delombok/UtilityClassInAnonymousClass.java new file mode 100644 index 00000000..3df9b559 --- /dev/null +++ b/test/transform/resource/after-delombok/UtilityClassInAnonymousClass.java @@ -0,0 +1,8 @@ +public class UtilityClassInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private String string; + } + }; +} diff --git a/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java b/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java new file mode 100644 index 00000000..a1176a3c --- /dev/null +++ b/test/transform/resource/after-delombok/ValAnonymousSubclassSelfReference.java @@ -0,0 +1,17 @@ +import java.util.Map; +import java.util.HashMap; + +public class ValAnonymousSubclassSelfReference { + public <T> void test(T arg) { + T d = arg; + Integer[] e = new Integer[1]; + int[] f = new int[0]; + java.util.Map<java.lang.String, Integer> g = new HashMap<String, Integer>(); + Integer h = 0; + int i = 0; + final int j = 1; + final int k = 2; + new ValAnonymousSubclassSelfReference() { + }; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValInvalidParameter.java b/test/transform/resource/after-delombok/ValInvalidParameter.java new file mode 100644 index 00000000..f3d4229c --- /dev/null +++ b/test/transform/resource/after-delombok/ValInvalidParameter.java @@ -0,0 +1,29 @@ +public class ValInvalidParameter { + public void val() { + final java.lang.Object a = a(new NonExistingClass()); + final java.lang.Object b = a(a(new NonExistingClass())); + final java.lang.Object c = nonExisitingMethod(b(1)); + final java.lang.Object d = nonExistingObject.nonExistingMethod(); + final java.lang.Object e = b(1).nonExistingMethod(); + final java.lang.Object f = 1 > 2 ? a(new NonExistingClass()) : a(new NonExistingClass()); + final java.lang.Object g = b2(1); + final java.lang.Integer h = b2(a("a"), a(null)); + final int i = a(a(null)); + } + + public int a(String param) { + return 0; + } + + public int a(Integer param) { + return 0; + } + + public Integer b(int i) { + return i; + } + + public Integer b2(int i, int j) { + return i; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValSwitchExpression.java b/test/transform/resource/after-delombok/ValSwitchExpression.java index a8fa9b0f..ba26c137 100644 --- a/test/transform/resource/after-delombok/ValSwitchExpression.java +++ b/test/transform/resource/after-delombok/ValSwitchExpression.java @@ -1,9 +1,9 @@ // version 14: public class ValSwitchExpression { public void method(int arg) { - final int x = switch (arg) { + final var x = switch (arg) { default -> { - final java.lang.String s = "string"; + final var s = "string"; yield arg; } }; diff --git a/test/transform/resource/after-delombok/ValToNative.java b/test/transform/resource/after-delombok/ValToNative.java new file mode 100644 index 00000000..64aff9e5 --- /dev/null +++ b/test/transform/resource/after-delombok/ValToNative.java @@ -0,0 +1,15 @@ +// version 10: +import java.io.IOException; +import java.util.Arrays; + +public class ValToNative { + private void test() throws IOException { + final var intField = 1; + for (final var s : Arrays.asList("1")) { + final var s2 = s; + } + try (var in = getClass().getResourceAsStream("ValToNative.class")) { + final var j = in.read(); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValueInAnonymousClass.java b/test/transform/resource/after-delombok/ValueInAnonymousClass.java new file mode 100644 index 00000000..5bab4093 --- /dev/null +++ b/test/transform/resource/after-delombok/ValueInAnonymousClass.java @@ -0,0 +1,46 @@ +public class ValueInAnonymousClass { + Object annonymous = new Object() { + + final class Inner { + private final String string; + + @java.lang.SuppressWarnings("all") + public Inner(final String string) { + this.string = string; + } + + @java.lang.SuppressWarnings("all") + public String getString() { + return this.string; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Inner)) return false; + final Inner other = (Inner) o; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (this$string == null ? other$string != null : !this$string.equals(other$string)) return false; + return true; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = result * PRIME + ($string == null ? 43 : $string.hashCode()); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Inner(string=" + this.getString() + ")"; + } + } + }; +} diff --git a/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..543481e8 --- /dev/null +++ b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,33 @@ +final class ValueWithJavaBeansSpecCapitalization { + private final int aField; + @java.lang.SuppressWarnings("all") + public ValueWithJavaBeansSpecCapitalization(final int aField) { + this.aField = aField; + } + @java.lang.SuppressWarnings("all") + public int getaField() { + return this.aField; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueWithJavaBeansSpecCapitalization)) return false; + final ValueWithJavaBeansSpecCapitalization other = (ValueWithJavaBeansSpecCapitalization) o; + if (this.getaField() != other.getaField()) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getaField(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField() + ")"; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/WithByInAnonymousClass.java b/test/transform/resource/after-delombok/WithByInAnonymousClass.java new file mode 100644 index 00000000..d84955b6 --- /dev/null +++ b/test/transform/resource/after-delombok/WithByInAnonymousClass.java @@ -0,0 +1,17 @@ +//version 8: +public class WithByInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private Inner(String string) { + } + + private String string; + + @java.lang.SuppressWarnings("all") + public Inner withStringBy(final java.util.function.Function<? super String, ? extends String> transformer) { + return new Inner(transformer.apply(this.string)); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/WithInAnonymousClass.java b/test/transform/resource/after-delombok/WithInAnonymousClass.java new file mode 100644 index 00000000..02490533 --- /dev/null +++ b/test/transform/resource/after-delombok/WithInAnonymousClass.java @@ -0,0 +1,19 @@ +public class WithInAnonymousClass { + Object annonymous = new Object() { + + class Inner { + private Inner(String string) { + } + + private String string; + + /** + * @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 Inner withString(final String string) { + return this.string == string ? this : new Inner(string); + } + } + }; +} diff --git a/test/transform/resource/after-delombok/WithWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/WithWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..e3737848 --- /dev/null +++ b/test/transform/resource/after-delombok/WithWithJavaBeansSpecCapitalization.java @@ -0,0 +1,12 @@ +class WithWithJavaBeansSpecCapitalization { + int aField; + WithWithJavaBeansSpecCapitalization(int aField) { + } + /** + * @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 WithWithJavaBeansSpecCapitalization withaField(final int aField) { + return this.aField == aField ? this : new WithWithJavaBeansSpecCapitalization(aField); + } +} diff --git a/test/transform/resource/after-ecj/AccessorsInAnonymousClass.java b/test/transform/resource/after-ecj/AccessorsInAnonymousClass.java new file mode 100644 index 00000000..34db4f2d --- /dev/null +++ b/test/transform/resource/after-ecj/AccessorsInAnonymousClass.java @@ -0,0 +1,29 @@ +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +public class AccessorsInAnonymousClass { + Object annonymous = new Object() { + @Getter @Setter @Accessors(fluent = true) class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.SuppressWarnings("all") String string() { + return this.string; + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") Inner string(final String string) { + this.string = string; + return this; + } + } + x() { + super(); + } + }; + public AccessorsInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/BuilderInAnonymousClass.java b/test/transform/resource/after-ecj/BuilderInAnonymousClass.java new file mode 100644 index 00000000..67660822 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderInAnonymousClass.java @@ -0,0 +1,17 @@ +import lombok.Builder; +public class BuilderInAnonymousClass { + Object annonymous = new Object() { + @Builder class Inner { + private String string; + Inner() { + super(); + } + } + x() { + super(); + } + }; + public BuilderInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/BuilderNestedInEnum.java b/test/transform/resource/after-ecj/BuilderNestedInEnum.java new file mode 100644 index 00000000..b3fb54f3 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderNestedInEnum.java @@ -0,0 +1,68 @@ +class BuilderNestedInEnum { + public enum TestEnum { + public static final @lombok.Builder @lombok.Value class TestBuilder { + public static @java.lang.SuppressWarnings("all") class TestBuilderBuilder { + private @java.lang.SuppressWarnings("all") String field; + @java.lang.SuppressWarnings("all") TestBuilderBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder field(final String field) { + this.field = field; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderNestedInEnum.TestEnum.TestBuilder build() { + return new BuilderNestedInEnum.TestEnum.TestBuilder(this.field); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(field=" + this.field) + ")"); + } + } + private final String field; + @java.lang.SuppressWarnings("all") TestBuilder(final String field) { + super(); + this.field = field; + } + public static @java.lang.SuppressWarnings("all") BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder builder() { + return new BuilderNestedInEnum.TestEnum.TestBuilder.TestBuilderBuilder(); + } + public @java.lang.SuppressWarnings("all") String getField() { + return this.field; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof BuilderNestedInEnum.TestEnum.TestBuilder))) + return false; + final BuilderNestedInEnum.TestEnum.TestBuilder other = (BuilderNestedInEnum.TestEnum.TestBuilder) o; + final java.lang.Object this$field = this.getField(); + final java.lang.Object other$field = other.getField(); + if (((this$field == null) ? (other$field != null) : (! this$field.equals(other$field)))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $field = this.getField(); + result = ((result * PRIME) + (($field == null) ? 43 : $field.hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("BuilderNestedInEnum.TestEnum.TestBuilder(field=" + this.getField()) + ")"); + } + } + FOO(), + BAR(), + <clinit>() { + } + public TestEnum() { + super(); + } + } + BuilderNestedInEnum() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/BuilderWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..1107254f --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderWithJavaBeansSpecCapitalization.java @@ -0,0 +1,99 @@ +@lombok.Builder(setterPrefix = "set") class BuilderWithJavaBeansSpecCapitalization { + public static @java.lang.SuppressWarnings("all") class BuilderWithJavaBeansSpecCapitalizationBuilder { + private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> a; + private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> aField; + private @java.lang.SuppressWarnings("all") String bField; + @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalizationBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setZ(final String z) { + if ((this.a == null)) + this.a = new java.util.ArrayList<String>(); + this.a.add(z); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setA(final java.util.Collection<? extends String> a) { + if ((a == null)) + { + throw new java.lang.NullPointerException("a cannot be null"); + } + if ((this.a == null)) + this.a = new java.util.ArrayList<String>(); + this.a.addAll(a); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearA() { + if ((this.a != null)) + this.a.clear(); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setyField(final String yField) { + if ((this.aField == null)) + this.aField = new java.util.ArrayList<String>(); + this.aField.add(yField); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setaField(final java.util.Collection<? extends String> aField) { + if ((aField == null)) + { + throw new java.lang.NullPointerException("aField cannot be null"); + } + if ((this.aField == null)) + this.aField = new java.util.ArrayList<String>(); + this.aField.addAll(aField); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder clearaField() { + if ((this.aField != null)) + this.aField.clear(); + return this; + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder setbField(final String bField) { + this.bField = bField; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization build() { + java.util.List<String> a; + switch (((this.a == null) ? 0 : this.a.size())) { + case 0 : + a = java.util.Collections.emptyList(); + break; + case 1 : + a = java.util.Collections.singletonList(this.a.get(0)); + break; + default : + a = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(this.a)); + } + java.util.List<String> aField; + switch (((this.aField == null) ? 0 : this.aField.size())) { + case 0 : + aField = java.util.Collections.emptyList(); + break; + case 1 : + aField = java.util.Collections.singletonList(this.aField.get(0)); + break; + default : + aField = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(this.aField)); + } + return new BuilderWithJavaBeansSpecCapitalization(a, aField, this.bField); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((("BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(a=" + this.a) + ", aField=") + this.aField) + ", bField=") + this.bField) + ")"); + } + } + @lombok.Singular("z") java.util.List<String> a; + @lombok.Singular("yField") java.util.List<String> aField; + String bField; + @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization(final java.util.List<String> a, final java.util.List<String> aField, final String bField) { + super(); + this.a = a; + this.aField = aField; + this.bField = bField; + } + public static @java.lang.SuppressWarnings("all") BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder builder() { + return new BuilderWithJavaBeansSpecCapitalization.BuilderWithJavaBeansSpecCapitalizationBuilder(); + } +} diff --git a/test/transform/resource/after-ecj/ConstructorsInAnonymousClass.java b/test/transform/resource/after-ecj/ConstructorsInAnonymousClass.java new file mode 100644 index 00000000..545ab04d --- /dev/null +++ b/test/transform/resource/after-ecj/ConstructorsInAnonymousClass.java @@ -0,0 +1,38 @@ +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +public class ConstructorsInAnonymousClass { + Object annonymous = new Object() { + @AllArgsConstructor @RequiredArgsConstructor @NoArgsConstructor class Inner { + private String string; + private @NonNull String string2; + public @java.lang.SuppressWarnings("all") Inner(final String string, final @NonNull String string2) { + super(); + if ((string2 == null)) + { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string = string; + this.string2 = string2; + } + public @java.lang.SuppressWarnings("all") Inner(final @NonNull String string2) { + super(); + if ((string2 == null)) + { + throw new java.lang.NullPointerException("string2 is marked non-null but is null"); + } + this.string2 = string2; + } + public @java.lang.SuppressWarnings("all") Inner() { + super(); + } + } + x() { + super(); + } + }; + public ConstructorsInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/DataInAnonymousClass.java b/test/transform/resource/after-ecj/DataInAnonymousClass.java new file mode 100644 index 00000000..c6e22f80 --- /dev/null +++ b/test/transform/resource/after-ecj/DataInAnonymousClass.java @@ -0,0 +1,50 @@ +import lombok.Data; +public class DataInAnonymousClass { + Object annonymous = new Object() { + @Data class Inner { + private String string; + public @java.lang.SuppressWarnings("all") String getString() { + return this.string; + } + public @java.lang.SuppressWarnings("all") void setString(final String string) { + this.string = string; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Inner))) + return false; + final Inner other = (Inner) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (((this$string == null) ? (other$string != null) : (! this$string.equals(other$string)))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Inner); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = ((result * PRIME) + (($string == null) ? 43 : $string.hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("Inner(string=" + this.getString()) + ")"); + } + public @java.lang.SuppressWarnings("all") Inner() { + super(); + } + } + x() { + super(); + } + }; + public DataInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeInAnonymousClass.java b/test/transform/resource/after-ecj/EqualsAndHashCodeInAnonymousClass.java new file mode 100644 index 00000000..e66850bb --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeInAnonymousClass.java @@ -0,0 +1,41 @@ +import lombok.EqualsAndHashCode; +public class EqualsAndHashCodeInAnonymousClass { + Object annonymous = new Object() { + @EqualsAndHashCode class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Inner))) + return false; + final Inner other = (Inner) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + final java.lang.Object this$string = this.string; + final java.lang.Object other$string = other.string; + if (((this$string == null) ? (other$string != null) : (! this$string.equals(other$string)))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Inner); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.string; + result = ((result * PRIME) + (($string == null) ? 43 : $string.hashCode())); + return result; + } + } + x() { + super(); + } + }; + public EqualsAndHashCodeInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/FieldDefaultsViaConfigOnRecord.java b/test/transform/resource/after-ecj/FieldDefaultsViaConfigOnRecord.java new file mode 100644 index 00000000..44ef0d4c --- /dev/null +++ b/test/transform/resource/after-ecj/FieldDefaultsViaConfigOnRecord.java @@ -0,0 +1,10 @@ +// version 14: +public record FieldDefaultsViaConfigOnRecord(String a, String b) { +/* Implicit */ private final String a; +/* Implicit */ private final String b; + public FieldDefaultsViaConfigOnRecord(String a, String b) { + super(); + .a = a; + .b = b; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/FieldNameConstantsInAnonymousClass.java b/test/transform/resource/after-ecj/FieldNameConstantsInAnonymousClass.java new file mode 100644 index 00000000..b04bef51 --- /dev/null +++ b/test/transform/resource/after-ecj/FieldNameConstantsInAnonymousClass.java @@ -0,0 +1,17 @@ +import lombok.experimental.FieldNameConstants; +public class FieldNameConstantsInAnonymousClass { + Object annonymous = new Object() { + @FieldNameConstants class Inner { + private String string; + Inner() { + super(); + } + } + x() { + super(); + } + }; + public FieldNameConstantsInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/GetterInAnonymousClass.java b/test/transform/resource/after-ecj/GetterInAnonymousClass.java new file mode 100644 index 00000000..30e6338d --- /dev/null +++ b/test/transform/resource/after-ecj/GetterInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.Getter; +public class GetterInAnonymousClass { + Object annonymous = new Object() { + @Getter class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.SuppressWarnings("all") String getString() { + return this.string; + } + } + x() { + super(); + } + }; + public GetterInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java b/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java new file mode 100644 index 00000000..ab8bc599 --- /dev/null +++ b/test/transform/resource/after-ecj/GetterLazyInAnonymousClass.java @@ -0,0 +1,34 @@ +import lombok.Getter; +public class GetterLazyInAnonymousClass { + Object annonymous = new Object() { + class Inner { + private final @Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.lang.Object> string = new java.util.concurrent.atomic.AtomicReference<java.lang.Object>(); + Inner() { + super(); + } + public @java.lang.SuppressWarnings({"all", "unchecked"}) String getString() { + java.lang.Object value = this.string.get(); + if ((value == null)) + { + synchronized (this.string) + { + value = this.string.get(); + if ((value == null)) + { + final String actualValue = "test"; + value = ((actualValue == null) ? this.string : actualValue); + this.string.set(value); + } + } + } + return (String) ((value == this.string) ? null : value); + } + } + x() { + super(); + } + }; + public GetterLazyInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..745529a0 --- /dev/null +++ b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,13 @@ +class GetterWithJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; + GetterWithJavaBeansSpecCapitalization() { + super(); + } + public @java.lang.SuppressWarnings("all") int getA() { + return this.a; + } + public @java.lang.SuppressWarnings("all") int getaField() { + return this.aField; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4jInAnonymousClass.java b/test/transform/resource/after-ecj/LoggerSlf4jInAnonymousClass.java new file mode 100644 index 00000000..0c78a288 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jInAnonymousClass.java @@ -0,0 +1,16 @@ +import lombok.extern.slf4j.Slf4j; +public class LoggerSlf4jInAnonymousClass { + Object annonymous = new Object() { + @Slf4j class Inner { + Inner() { + super(); + } + } + x() { + super(); + } + }; + public LoggerSlf4jInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SetterInAnonymousClass.java b/test/transform/resource/after-ecj/SetterInAnonymousClass.java new file mode 100644 index 00000000..fc0bf2d8 --- /dev/null +++ b/test/transform/resource/after-ecj/SetterInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.Setter; +public class SetterInAnonymousClass { + Object annonymous = new Object() { + @Setter class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.SuppressWarnings("all") void setString(final String string) { + this.string = string; + } + } + x() { + super(); + } + }; + public SetterInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..4e99890a --- /dev/null +++ b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,13 @@ +class SetterWithJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; + SetterWithJavaBeansSpecCapitalization() { + super(); + } + public @java.lang.SuppressWarnings("all") void setA(final int a) { + this.a = a; + } + public @java.lang.SuppressWarnings("all") void setaField(final int aField) { + this.aField = aField; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/SuperBuilderInAnonymousClass.java b/test/transform/resource/after-ecj/SuperBuilderInAnonymousClass.java new file mode 100644 index 00000000..238f42df --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderInAnonymousClass.java @@ -0,0 +1,23 @@ +import lombok.experimental.SuperBuilder; +public class SuperBuilderInAnonymousClass { + Object annonymous = new Object() { + @SuperBuilder class InnerParent { + private String string; + InnerParent() { + super(); + } + } + @SuperBuilder class InnerChild { + private String string; + InnerChild() { + super(); + } + } + x() { + super(); + } + }; + public SuperBuilderInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SynchronizedInAnonymousClass.java b/test/transform/resource/after-ecj/SynchronizedInAnonymousClass.java new file mode 100644 index 00000000..77013f2f --- /dev/null +++ b/test/transform/resource/after-ecj/SynchronizedInAnonymousClass.java @@ -0,0 +1,23 @@ +import lombok.Synchronized; +public class SynchronizedInAnonymousClass { + Object annonymous = new Object() { + class Inner { + private final java.lang.Object $lock = new java.lang.Object[0]; + Inner() { + super(); + } + public @Synchronized void foo() { + synchronized (this.$lock) + { + String foo = "bar"; + } + } + } + x() { + super(); + } + }; + public SynchronizedInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/ToStringInAnonymousClass.java b/test/transform/resource/after-ecj/ToStringInAnonymousClass.java new file mode 100644 index 00000000..02ad2a88 --- /dev/null +++ b/test/transform/resource/after-ecj/ToStringInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.ToString; +public class ToStringInAnonymousClass { + Object annonymous = new Object() { + @ToString class Inner { + private String string; + Inner() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("Inner(string=" + this.string) + ")"); + } + } + x() { + super(); + } + }; + public ToStringInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/UtilityClassInAnonymousClass.java b/test/transform/resource/after-ecj/UtilityClassInAnonymousClass.java new file mode 100644 index 00000000..e836636d --- /dev/null +++ b/test/transform/resource/after-ecj/UtilityClassInAnonymousClass.java @@ -0,0 +1,17 @@ +import lombok.experimental.UtilityClass; +public class UtilityClassInAnonymousClass { + Object annonymous = new Object() { + @UtilityClass class Inner { + private String string; + Inner() { + super(); + } + } + x() { + super(); + } + }; + public UtilityClassInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java b/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java new file mode 100644 index 00000000..12b0f640 --- /dev/null +++ b/test/transform/resource/after-ecj/ValAnonymousSubclassSelfReference.java @@ -0,0 +1,23 @@ +import java.util.Map; +import java.util.HashMap; +import lombok.val; +public class ValAnonymousSubclassSelfReference { + public ValAnonymousSubclassSelfReference() { + super(); + } + public <T>void test(T arg) { + T d = arg; + Integer[] e = new Integer[1]; + int[] f = new int[0]; + java.util.Map<java.lang.String, Integer> g = new HashMap<String, Integer>(); + Integer h = 0; + int i = 0; + final @val int j = 1; + final @val int k = 2; + new ValAnonymousSubclassSelfReference() { + x() { + super(); + } + }; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValErrors.java b/test/transform/resource/after-ecj/ValErrors.java index 1bd61f87..19c2facd 100644 --- a/test/transform/resource/after-ecj/ValErrors.java +++ b/test/transform/resource/after-ecj/ValErrors.java @@ -4,9 +4,9 @@ public class ValErrors { super(); } public void unresolvableExpression() { - val c = d; + final @val java.lang.Object c = d; } public void arrayInitializer() { - val e = {"foo", "bar"}; + final @val java.lang.Object e = {"foo", "bar"}; } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValInvalidParameter.java b/test/transform/resource/after-ecj/ValInvalidParameter.java new file mode 100644 index 00000000..14549aa7 --- /dev/null +++ b/test/transform/resource/after-ecj/ValInvalidParameter.java @@ -0,0 +1,29 @@ +import lombok.val; +public class ValInvalidParameter { + public ValInvalidParameter() { + super(); + } + public void val() { + final @val java.lang.Object a = a(new NonExistingClass()); + final @val java.lang.Object b = a(a(new NonExistingClass())); + final @val java.lang.Object c = nonExisitingMethod(b(1)); + final @val java.lang.Object d = nonExistingObject.nonExistingMethod(); + final @val java.lang.Object e = b(1).nonExistingMethod(); + final @val java.lang.Object f = ((1 > 2) ? a(new NonExistingClass()) : a(new NonExistingClass())); + final @val java.lang.Object g = b2(1); + final @val java.lang.Object h = b2(a("a"), a(null)); + final @val java.lang.Object i = a(a(null)); + } + public int a(String param) { + return 0; + } + public int a(Integer param) { + return 0; + } + public Integer b(int i) { + return i; + } + public Integer b2(int i, int j) { + return i; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValSwitchExpression.java b/test/transform/resource/after-ecj/ValSwitchExpression.java index 59b503cb..4e848572 100644 --- a/test/transform/resource/after-ecj/ValSwitchExpression.java +++ b/test/transform/resource/after-ecj/ValSwitchExpression.java @@ -5,10 +5,10 @@ public class ValSwitchExpression { super(); } public void method(int arg) { - final @val int x = switch (arg) { + final @val var x = switch (arg) { default -> { - final @val java.lang.String s = "string"; + final @val var s = "string"; yield arg; } }; diff --git a/test/transform/resource/after-ecj/ValToNative.java b/test/transform/resource/after-ecj/ValToNative.java new file mode 100644 index 00000000..2c8d721c --- /dev/null +++ b/test/transform/resource/after-ecj/ValToNative.java @@ -0,0 +1,19 @@ +import java.io.IOException; +import java.util.Arrays; +import lombok.val; +public class ValToNative { + public ValToNative() { + super(); + } + private void test() throws IOException { + final @val var intField = 1; + for (final @val var s : Arrays.asList("1")) + { + final @val var s2 = s; + } + try (final @val var in = getClass().getResourceAsStream("ValToNative.class")) + { + final @val var j = in.read(); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValueInAnonymousClass.java b/test/transform/resource/after-ecj/ValueInAnonymousClass.java new file mode 100644 index 00000000..49cf8fc2 --- /dev/null +++ b/test/transform/resource/after-ecj/ValueInAnonymousClass.java @@ -0,0 +1,43 @@ +import lombok.Value; +public class ValueInAnonymousClass { + Object annonymous = new Object() { + final @Value class Inner { + private final String string; + public @java.lang.SuppressWarnings("all") String getString() { + return this.string; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Inner))) + return false; + final Inner other = (Inner) o; + final java.lang.Object this$string = this.getString(); + final java.lang.Object other$string = other.getString(); + if (((this$string == null) ? (other$string != null) : (! this$string.equals(other$string)))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + final java.lang.Object $string = this.getString(); + result = ((result * PRIME) + (($string == null) ? 43 : $string.hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("Inner(string=" + this.getString()) + ")"); + } + public @java.lang.SuppressWarnings("all") Inner(final String string) { + super(); + this.string = string; + } + } + x() { + super(); + } + }; + public ValueInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..8117dbb0 --- /dev/null +++ b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,29 @@ +final @lombok.Value class ValueWithJavaBeansSpecCapitalization { + private final int aField; + public @java.lang.SuppressWarnings("all") int getaField() { + return this.aField; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueWithJavaBeansSpecCapitalization))) + return false; + final ValueWithJavaBeansSpecCapitalization other = (ValueWithJavaBeansSpecCapitalization) o; + if ((this.getaField() != other.getaField())) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getaField()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField()) + ")"); + } + public @java.lang.SuppressWarnings("all") ValueWithJavaBeansSpecCapitalization(final int aField) { + super(); + this.aField = aField; + } +} diff --git a/test/transform/resource/after-ecj/WithByInAnonymousClass.java b/test/transform/resource/after-ecj/WithByInAnonymousClass.java new file mode 100644 index 00000000..1bc3e80c --- /dev/null +++ b/test/transform/resource/after-ecj/WithByInAnonymousClass.java @@ -0,0 +1,20 @@ +import lombok.experimental.WithBy; +public class WithByInAnonymousClass { + Object annonymous = new Object() { + @WithBy class Inner { + private String string; + private Inner(String string) { + super(); + } + public @java.lang.SuppressWarnings("all") Inner withStringBy(final java.util.function.Function<? super String, ? extends String> transformer) { + return new Inner(transformer.apply(this.string)); + } + } + x() { + super(); + } + }; + public WithByInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/WithInAnonymousClass.java b/test/transform/resource/after-ecj/WithInAnonymousClass.java new file mode 100644 index 00000000..fef96022 --- /dev/null +++ b/test/transform/resource/after-ecj/WithInAnonymousClass.java @@ -0,0 +1,23 @@ +import lombok.With; +public class WithInAnonymousClass { + Object annonymous = new Object() { + @With class Inner { + private String string; + private Inner(String string) { + super(); + } + /** + * @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") Inner withString(final String string) { + return ((this.string == string) ? this : new Inner(string)); + } + } + x() { + super(); + } + }; + public WithInAnonymousClass() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..fb035da4 --- /dev/null +++ b/test/transform/resource/after-ecj/WithWithJavaBeansSpecCapitalization.java @@ -0,0 +1,12 @@ +@lombok.With class WithWithJavaBeansSpecCapitalization { + int aField; + WithWithJavaBeansSpecCapitalization(int aField) { + super(); + } + /** + * @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") WithWithJavaBeansSpecCapitalization withaField(final int aField) { + return ((this.aField == aField) ? this : new WithWithJavaBeansSpecCapitalization(aField)); + } +} diff --git a/test/transform/resource/before/AccessorsInAnonymousClass.java b/test/transform/resource/before/AccessorsInAnonymousClass.java new file mode 100644 index 00000000..0bbab1d6 --- /dev/null +++ b/test/transform/resource/before/AccessorsInAnonymousClass.java @@ -0,0 +1,14 @@ +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +public class AccessorsInAnonymousClass { + Object annonymous = new Object() { + @Getter + @Setter + @Accessors(fluent = true) + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/BuilderInAnonymousClass.java b/test/transform/resource/before/BuilderInAnonymousClass.java new file mode 100644 index 00000000..8291e678 --- /dev/null +++ b/test/transform/resource/before/BuilderInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Builder; + +public class BuilderInAnonymousClass { + Object annonymous = new Object() { + @Builder + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/BuilderNestedInEnum.java b/test/transform/resource/before/BuilderNestedInEnum.java new file mode 100644 index 00000000..99348002 --- /dev/null +++ b/test/transform/resource/before/BuilderNestedInEnum.java @@ -0,0 +1,12 @@ +// issue #3014: Builder check if its on a non-static inner class and errors if it is. But it was erroring here even though it is on a static inner class. +class BuilderNestedInEnum { + public enum TestEnum { + FOO, BAR; + + @lombok.Builder + @lombok.Value + public static class TestBuilder { + String field; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/BuilderWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/BuilderWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..db1fe15f --- /dev/null +++ b/test/transform/resource/before/BuilderWithJavaBeansSpecCapitalization.java @@ -0,0 +1,7 @@ +//CONF: lombok.accessors.capitalization = beanspec +@lombok.Builder(setterPrefix = "set") +class BuilderWithJavaBeansSpecCapitalization { + @lombok.Singular("z") java.util.List<String> a; + @lombok.Singular("yField") java.util.List<String> aField; + String bField; +} diff --git a/test/transform/resource/before/ConstructorsInAnonymousClass.java b/test/transform/resource/before/ConstructorsInAnonymousClass.java new file mode 100644 index 00000000..a74a7f11 --- /dev/null +++ b/test/transform/resource/before/ConstructorsInAnonymousClass.java @@ -0,0 +1,18 @@ +//version 8: +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +public class ConstructorsInAnonymousClass { + Object annonymous = new Object() { + @AllArgsConstructor + @RequiredArgsConstructor + @NoArgsConstructor + class Inner { + private String string; + @NonNull + private String string2; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/DataInAnonymousClass.java b/test/transform/resource/before/DataInAnonymousClass.java new file mode 100644 index 00000000..3de5ac0b --- /dev/null +++ b/test/transform/resource/before/DataInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Data; + +public class DataInAnonymousClass { + Object annonymous = new Object() { + @Data + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/EqualsAndHashCodeInAnonymousClass.java b/test/transform/resource/before/EqualsAndHashCodeInAnonymousClass.java new file mode 100644 index 00000000..0f0995b6 --- /dev/null +++ b/test/transform/resource/before/EqualsAndHashCodeInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.EqualsAndHashCode; + +public class EqualsAndHashCodeInAnonymousClass { + Object annonymous = new Object() { + @EqualsAndHashCode + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/FieldDefaultsViaConfigOnRecord.java b/test/transform/resource/before/FieldDefaultsViaConfigOnRecord.java new file mode 100644 index 00000000..e72179e9 --- /dev/null +++ b/test/transform/resource/before/FieldDefaultsViaConfigOnRecord.java @@ -0,0 +1,7 @@ +// version 14: +//CONF: lombok.fieldDefaults.defaultFinal = true +//CONF: lombok.fieldDefaults.defaultPrivate = true +//unchanged + +public record FieldDefaultsViaConfigOnRecord(String a, String b) { +}
\ No newline at end of file diff --git a/test/transform/resource/before/FieldNameConstantsInAnonymousClass.java b/test/transform/resource/before/FieldNameConstantsInAnonymousClass.java new file mode 100644 index 00000000..86325ce5 --- /dev/null +++ b/test/transform/resource/before/FieldNameConstantsInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.experimental.FieldNameConstants; + +public class FieldNameConstantsInAnonymousClass { + Object annonymous = new Object() { + @FieldNameConstants + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/GetterInAnonymousClass.java b/test/transform/resource/before/GetterInAnonymousClass.java new file mode 100644 index 00000000..e8195021 --- /dev/null +++ b/test/transform/resource/before/GetterInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Getter; + +public class GetterInAnonymousClass { + Object annonymous = new Object() { + @Getter + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/GetterLazyInAnonymousClass.java b/test/transform/resource/before/GetterLazyInAnonymousClass.java new file mode 100644 index 00000000..e342e636 --- /dev/null +++ b/test/transform/resource/before/GetterLazyInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Getter; + +public class GetterLazyInAnonymousClass { + Object annonymous = new Object() { + class Inner { + @Getter(lazy = true) + private final String string = "test"; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..68f41e3d --- /dev/null +++ b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,5 @@ +//CONF: lombok.accessors.capitalization = beanspec +class GetterWithJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; +} diff --git a/test/transform/resource/before/LoggerSlf4jInAnonymousClass.java b/test/transform/resource/before/LoggerSlf4jInAnonymousClass.java new file mode 100644 index 00000000..4839c7aa --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jInAnonymousClass.java @@ -0,0 +1,9 @@ +import lombok.extern.slf4j.Slf4j; + +public class LoggerSlf4jInAnonymousClass { + Object annonymous = new Object() { + @Slf4j + class Inner { + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/MixGetterVal.java b/test/transform/resource/before/MixGetterVal.java index 3f06b1a8..4568902b 100644 --- a/test/transform/resource/before/MixGetterVal.java +++ b/test/transform/resource/before/MixGetterVal.java @@ -1,3 +1,4 @@ +// version :9 import lombok.Getter; import lombok.val; diff --git a/test/transform/resource/before/SetterInAnonymousClass.java b/test/transform/resource/before/SetterInAnonymousClass.java new file mode 100644 index 00000000..1b3c817b --- /dev/null +++ b/test/transform/resource/before/SetterInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Setter; + +public class SetterInAnonymousClass { + Object annonymous = new Object() { + @Setter + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..b5e34ba7 --- /dev/null +++ b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,5 @@ +//CONF: lombok.accessors.capitalization = beanspec +class SetterWithJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; +} diff --git a/test/transform/resource/before/SuperBuilderInAnonymousClass.java b/test/transform/resource/before/SuperBuilderInAnonymousClass.java new file mode 100644 index 00000000..bff871aa --- /dev/null +++ b/test/transform/resource/before/SuperBuilderInAnonymousClass.java @@ -0,0 +1,15 @@ +import lombok.experimental.SuperBuilder; + +public class SuperBuilderInAnonymousClass { + Object annonymous = new Object() { + @SuperBuilder + class InnerParent { + private String string; + } + + @SuperBuilder + class InnerChild { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/SynchronizedInAnonymousClass.java b/test/transform/resource/before/SynchronizedInAnonymousClass.java new file mode 100644 index 00000000..11c623ce --- /dev/null +++ b/test/transform/resource/before/SynchronizedInAnonymousClass.java @@ -0,0 +1,12 @@ +import lombok.Synchronized; + +public class SynchronizedInAnonymousClass { + Object annonymous = new Object() { + class Inner { + @Synchronized + public void foo() { + String foo = "bar"; + } + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/ToStringInAnonymousClass.java b/test/transform/resource/before/ToStringInAnonymousClass.java new file mode 100644 index 00000000..87a7a6c1 --- /dev/null +++ b/test/transform/resource/before/ToStringInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.ToString; + +public class ToStringInAnonymousClass { + Object annonymous = new Object() { + @ToString + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/TrickyTypeResolution.java b/test/transform/resource/before/TrickyTypeResolution.java index 94d97fe0..7f3866ee 100644 --- a/test/transform/resource/before/TrickyTypeResolution.java +++ b/test/transform/resource/before/TrickyTypeResolution.java @@ -1,3 +1,4 @@ +// version :9 import lombok.*; class TrickyDoNothing { @interface Getter {} diff --git a/test/transform/resource/before/UtilityClassInAnonymousClass.java b/test/transform/resource/before/UtilityClassInAnonymousClass.java new file mode 100644 index 00000000..41757502 --- /dev/null +++ b/test/transform/resource/before/UtilityClassInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.experimental.UtilityClass; + +public class UtilityClassInAnonymousClass { + Object annonymous = new Object() { + @UtilityClass + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValAnonymousSubclassSelfReference.java b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java new file mode 100644 index 00000000..b17c997a --- /dev/null +++ b/test/transform/resource/before/ValAnonymousSubclassSelfReference.java @@ -0,0 +1,22 @@ +// version :9 +// issue 2420: to trigger the problem 2 var/val, at least one normal variable and a anonymous self reference is required +import java.util.Map; +import java.util.HashMap; + +import lombok.val; + +public class ValAnonymousSubclassSelfReference { + public <T> void test(T arg) { + T d = arg; + Integer[] e = new Integer[1]; + int[] f = new int[0]; + java.util.Map<java.lang.String, Integer> g = new HashMap<String, Integer>(); + Integer h = 0; + int i = 0; + + val j = 1; + val k = 2; + + new ValAnonymousSubclassSelfReference() { }; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java b/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java index c0f8157a..a434ba9d 100644 --- a/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java +++ b/test/transform/resource/before/ValAnonymousSubclassWithGenerics.java @@ -1,3 +1,4 @@ +// version :9 // issue 205: val inside anonymous inner classes is a bit tricky in javac, this test ensures we don't break it. import java.util.*; import lombok.val; diff --git a/test/transform/resource/before/ValComplex.java b/test/transform/resource/before/ValComplex.java index e20124a2..f1898cfd 100644 --- a/test/transform/resource/before/ValComplex.java +++ b/test/transform/resource/before/ValComplex.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValComplex { diff --git a/test/transform/resource/before/ValDefault.java b/test/transform/resource/before/ValDefault.java index 75124c3c..ded4b074 100644 --- a/test/transform/resource/before/ValDefault.java +++ b/test/transform/resource/before/ValDefault.java @@ -1,4 +1,4 @@ -// version 8: +// version 8:9 interface ValDefault { int size(); diff --git a/test/transform/resource/before/ValDelegateMethodReference.java b/test/transform/resource/before/ValDelegateMethodReference.java index 3d1f082c..8cfc2c33 100644 --- a/test/transform/resource/before/ValDelegateMethodReference.java +++ b/test/transform/resource/before/ValDelegateMethodReference.java @@ -1,4 +1,4 @@ -//version 8: +//version 8:9 //platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.Getter; import lombok.Setter; diff --git a/test/transform/resource/before/ValErrors.java b/test/transform/resource/before/ValErrors.java index 87383719..290a1f72 100644 --- a/test/transform/resource/before/ValErrors.java +++ b/test/transform/resource/before/ValErrors.java @@ -1,3 +1,4 @@ +// version :9 // unchanged import lombok.val; diff --git a/test/transform/resource/before/ValFinal.java b/test/transform/resource/before/ValFinal.java index 3c5af366..293c9bce 100644 --- a/test/transform/resource/before/ValFinal.java +++ b/test/transform/resource/before/ValFinal.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValFinal { public void test() { diff --git a/test/transform/resource/before/ValInBasicFor.java b/test/transform/resource/before/ValInBasicFor.java index a109bcd3..b137f0d7 100644 --- a/test/transform/resource/before/ValInBasicFor.java +++ b/test/transform/resource/before/ValInBasicFor.java @@ -1,3 +1,4 @@ +// version :9 // unchanged import lombok.val; diff --git a/test/transform/resource/before/ValInFor.java b/test/transform/resource/before/ValInFor.java index 35332b34..f2c50139 100644 --- a/test/transform/resource/before/ValInFor.java +++ b/test/transform/resource/before/ValInFor.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValInFor { diff --git a/test/transform/resource/before/ValInLambda.java b/test/transform/resource/before/ValInLambda.java index 6750d045..a13c79d2 100644 --- a/test/transform/resource/before/ValInLambda.java +++ b/test/transform/resource/before/ValInLambda.java @@ -1,4 +1,4 @@ -// version 8: +// version 8:9 import java.util.function.Function; import java.util.function.Supplier; diff --git a/test/transform/resource/before/ValInMultiDeclaration.java b/test/transform/resource/before/ValInMultiDeclaration.java index 1c333ebb..0f4e604b 100644 --- a/test/transform/resource/before/ValInMultiDeclaration.java +++ b/test/transform/resource/before/ValInMultiDeclaration.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValInMultiDeclaration { public void test() { diff --git a/test/transform/resource/before/ValInTryWithResources.java b/test/transform/resource/before/ValInTryWithResources.java index a7820062..5c885f79 100644 --- a/test/transform/resource/before/ValInTryWithResources.java +++ b/test/transform/resource/before/ValInTryWithResources.java @@ -1,4 +1,4 @@ -//version 7: +//version 7:9 import lombok.val; import java.io.IOException; diff --git a/test/transform/resource/before/ValInvalidParameter.java b/test/transform/resource/before/ValInvalidParameter.java new file mode 100644 index 00000000..f4961c4e --- /dev/null +++ b/test/transform/resource/before/ValInvalidParameter.java @@ -0,0 +1,32 @@ +//version :9 +import lombok.val; + +public class ValInvalidParameter { + public void val() { + val a = a(new NonExistingClass()); + val b = a(a(new NonExistingClass())); + val c = nonExisitingMethod(b(1)); + val d = nonExistingObject.nonExistingMethod(); + val e = b(1).nonExistingMethod(); + val f = 1 > 2 ? a(new NonExistingClass()) : a(new NonExistingClass()); + val g = b2(1); + val h = b2(a("a"), a(null)); + val i = a(a(null)); + } + + public int a(String param) { + return 0; + } + + public int a(Integer param) { + return 0; + } + + public Integer b(int i) { + return i; + } + + public Integer b2(int i, int j) { + return i; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValLambda.java b/test/transform/resource/before/ValLambda.java index e956bcd3..8f55d222 100644 --- a/test/transform/resource/before/ValLambda.java +++ b/test/transform/resource/before/ValLambda.java @@ -1,4 +1,4 @@ -// version 8: +// version 8:9 import java.io.Serializable; class ValLambda { diff --git a/test/transform/resource/before/ValLessSimple.java b/test/transform/resource/before/ValLessSimple.java index b81cc22c..1ed738cc 100644 --- a/test/transform/resource/before/ValLessSimple.java +++ b/test/transform/resource/before/ValLessSimple.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValLessSimple { diff --git a/test/transform/resource/before/ValLub.java b/test/transform/resource/before/ValLub.java index 509a4f8b..e3b55950 100644 --- a/test/transform/resource/before/ValLub.java +++ b/test/transform/resource/before/ValLub.java @@ -1,3 +1,4 @@ +// version :9 class ValLub { public void easyLub() { java.util.Map<String, Number> m = java.util.Collections.emptyMap(); diff --git a/test/transform/resource/before/ValNullInit.java b/test/transform/resource/before/ValNullInit.java index 649bc0cd..c1610af3 100644 --- a/test/transform/resource/before/ValNullInit.java +++ b/test/transform/resource/before/ValNullInit.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; class ValNullInit { diff --git a/test/transform/resource/before/ValOutersWithGenerics.java b/test/transform/resource/before/ValOutersWithGenerics.java index 1b29d37c..99b71735 100644 --- a/test/transform/resource/before/ValOutersWithGenerics.java +++ b/test/transform/resource/before/ValOutersWithGenerics.java @@ -1,3 +1,4 @@ +// version :9 import java.util.*; import lombok.val; diff --git a/test/transform/resource/before/ValRawType.java b/test/transform/resource/before/ValRawType.java index 3ef8527e..fa47c536 100644 --- a/test/transform/resource/before/ValRawType.java +++ b/test/transform/resource/before/ValRawType.java @@ -1,3 +1,4 @@ +// version :9 import java.util.List; import lombok.val; diff --git a/test/transform/resource/before/ValSimple.java b/test/transform/resource/before/ValSimple.java index 04763be2..5d1911da 100644 --- a/test/transform/resource/before/ValSimple.java +++ b/test/transform/resource/before/ValSimple.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValSimple { diff --git a/test/transform/resource/before/ValToNative.java b/test/transform/resource/before/ValToNative.java new file mode 100644 index 00000000..3b4e6fa8 --- /dev/null +++ b/test/transform/resource/before/ValToNative.java @@ -0,0 +1,19 @@ +// version 10: +import java.io.IOException; +import java.util.Arrays; + +import lombok.val; + +public class ValToNative { + private void test() throws IOException { + val intField = 1; + + for (val s : Arrays.asList("1")) { + val s2 = s; + } + + try (val in = getClass().getResourceAsStream("ValToNative.class")) { + val j = in.read(); + } + } +} diff --git a/test/transform/resource/before/ValWeirdTypes.java b/test/transform/resource/before/ValWeirdTypes.java index f62feca6..710e236b 100644 --- a/test/transform/resource/before/ValWeirdTypes.java +++ b/test/transform/resource/before/ValWeirdTypes.java @@ -1,4 +1,4 @@ -// version 8: In java6/7, lub types worked differently, so, the `arraysAsList` method has a slightly different inferred type there. +// version 8:9 In java6/7, lub types worked differently, so, the `arraysAsList` method has a slightly different inferred type there. import java.math.BigDecimal; import java.util.*; import lombok.val; diff --git a/test/transform/resource/before/ValWithLabel.java b/test/transform/resource/before/ValWithLabel.java index f7c3402a..9e15f937 100644 --- a/test/transform/resource/before/ValWithLabel.java +++ b/test/transform/resource/before/ValWithLabel.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValWithLabel { diff --git a/test/transform/resource/before/ValWithLocalClasses.java b/test/transform/resource/before/ValWithLocalClasses.java index 572a1e7d..0d145aa9 100644 --- a/test/transform/resource/before/ValWithLocalClasses.java +++ b/test/transform/resource/before/ValWithLocalClasses.java @@ -1,3 +1,4 @@ +// version :9 //issue 694: In javac, resolving the RHS (which is what val does) can cause an entire class to be resolved, breaking all usage of val inside that class. This tests that we handle that better. class ValWithLocalClasses1 { { diff --git a/test/transform/resource/before/ValWithSelfRefGenerics.java b/test/transform/resource/before/ValWithSelfRefGenerics.java index d0532606..fdb30d32 100644 --- a/test/transform/resource/before/ValWithSelfRefGenerics.java +++ b/test/transform/resource/before/ValWithSelfRefGenerics.java @@ -1,3 +1,4 @@ +// version :9 import lombok.val; public class ValWithSelfRefGenerics { public void run(Thing<? extends Comparable<?>> thing, Thing<?> thing2, java.util.List<? extends Number> z) { diff --git a/test/transform/resource/before/ValueInAnonymousClass.java b/test/transform/resource/before/ValueInAnonymousClass.java new file mode 100644 index 00000000..c0bde2ab --- /dev/null +++ b/test/transform/resource/before/ValueInAnonymousClass.java @@ -0,0 +1,10 @@ +import lombok.Value; + +public class ValueInAnonymousClass { + Object annonymous = new Object() { + @Value + class Inner { + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..7c001f6e --- /dev/null +++ b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,5 @@ +//CONF: lombok.accessors.capitalization = beanspec +@lombok.Value +class ValueWithJavaBeansSpecCapitalization { + final int aField; +} diff --git a/test/transform/resource/before/WithByInAnonymousClass.java b/test/transform/resource/before/WithByInAnonymousClass.java new file mode 100644 index 00000000..afed6adf --- /dev/null +++ b/test/transform/resource/before/WithByInAnonymousClass.java @@ -0,0 +1,13 @@ +//version 8: +import lombok.experimental.WithBy; + +public class WithByInAnonymousClass { + Object annonymous = new Object() { + @WithBy + class Inner { + private Inner(String string) { } + + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/WithInAnonymousClass.java b/test/transform/resource/before/WithInAnonymousClass.java new file mode 100644 index 00000000..daf1bce5 --- /dev/null +++ b/test/transform/resource/before/WithInAnonymousClass.java @@ -0,0 +1,12 @@ +import lombok.With; + +public class WithInAnonymousClass { + Object annonymous = new Object() { + @With + class Inner { + private Inner(String string) { } + + private String string; + } + }; +}
\ No newline at end of file diff --git a/test/transform/resource/before/WithWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/WithWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..ef4a78ad --- /dev/null +++ b/test/transform/resource/before/WithWithJavaBeansSpecCapitalization.java @@ -0,0 +1,8 @@ +//CONF: lombok.accessors.capitalization = beanspec +@lombok.With +class WithWithJavaBeansSpecCapitalization { + int aField; + + WithWithJavaBeansSpecCapitalization(int aField) { + } +} diff --git a/test/transform/resource/messages-delombok/BuilderInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/BuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..7607e734 --- /dev/null +++ b/test/transform/resource/messages-delombok/BuilderInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Builder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/FieldNameConstantsInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/FieldNameConstantsInAnonymousClass.java.messages new file mode 100644 index 00000000..b9d4887f --- /dev/null +++ b/test/transform/resource/messages-delombok/FieldNameConstantsInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @FieldNameConstants is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/LoggerSlf4jInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/LoggerSlf4jInAnonymousClass.java.messages new file mode 100644 index 00000000..d4da9f99 --- /dev/null +++ b/test/transform/resource/messages-delombok/LoggerSlf4jInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Slf4j is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/SuperBuilderInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/SuperBuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..f0cf3243 --- /dev/null +++ b/test/transform/resource/messages-delombok/SuperBuilderInAnonymousClass.java.messages @@ -0,0 +1,2 @@ +5 @SuperBuilder is not supported on non-static nested classes. +10 @SuperBuilder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-delombok/UtilityClassInAnonymousClass.java.messages b/test/transform/resource/messages-delombok/UtilityClassInAnonymousClass.java.messages new file mode 100644 index 00000000..8884e02d --- /dev/null +++ b/test/transform/resource/messages-delombok/UtilityClassInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @UtilityClass automatically makes the class static, however, this class cannot be made static. diff --git a/test/transform/resource/messages-delombok/ValInvalidParameter.java.messages b/test/transform/resource/messages-delombok/ValInvalidParameter.java.messages new file mode 100644 index 00000000..da0df315 --- /dev/null +++ b/test/transform/resource/messages-delombok/ValInvalidParameter.java.messages @@ -0,0 +1 @@ +12 Cannot use 'val' here because initializer expression does not have a representable type: Type cannot be resolved
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/BuilderInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/BuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..7607e734 --- /dev/null +++ b/test/transform/resource/messages-ecj/BuilderInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Builder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/FieldNameConstantsInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/FieldNameConstantsInAnonymousClass.java.messages new file mode 100644 index 00000000..b9d4887f --- /dev/null +++ b/test/transform/resource/messages-ecj/FieldNameConstantsInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @FieldNameConstants is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/LoggerSlf4jInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/LoggerSlf4jInAnonymousClass.java.messages new file mode 100644 index 00000000..d4da9f99 --- /dev/null +++ b/test/transform/resource/messages-ecj/LoggerSlf4jInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @Slf4j is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/SuperBuilderInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/SuperBuilderInAnonymousClass.java.messages new file mode 100644 index 00000000..f0cf3243 --- /dev/null +++ b/test/transform/resource/messages-ecj/SuperBuilderInAnonymousClass.java.messages @@ -0,0 +1,2 @@ +5 @SuperBuilder is not supported on non-static nested classes. +10 @SuperBuilder is not supported on non-static nested classes. diff --git a/test/transform/resource/messages-ecj/UtilityClassInAnonymousClass.java.messages b/test/transform/resource/messages-ecj/UtilityClassInAnonymousClass.java.messages new file mode 100644 index 00000000..8884e02d --- /dev/null +++ b/test/transform/resource/messages-ecj/UtilityClassInAnonymousClass.java.messages @@ -0,0 +1 @@ +5 @UtilityClass automatically makes the class static, however, this class cannot be made static. diff --git a/test/transform/resource/messages-ecj/ValErrors.java.messages b/test/transform/resource/messages-ecj/ValErrors.java.messages index c4c76901..9fcec493 100644 --- a/test/transform/resource/messages-ecj/ValErrors.java.messages +++ b/test/transform/resource/messages-ecj/ValErrors.java.messages @@ -1,2 +1,4 @@ -6 d cannot be resolved to a variable -10 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... }) +7 d cannot be resolved to a variable +7 d cannot be resolved or is not a field +11 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... }) +11 Type mismatch: cannot convert from String[] to Object
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/ValInBasicFor.java.messages b/test/transform/resource/messages-ecj/ValInBasicFor.java.messages index b32eabe4..00bc643f 100644 --- a/test/transform/resource/messages-ecj/ValInBasicFor.java.messages +++ b/test/transform/resource/messages-ecj/ValInBasicFor.java.messages @@ -1,2 +1,4 @@ -7 'val' is not allowed in old-style for loops -7 Type mismatch: cannot convert from int to val +8 'val' is not allowed in old-style for loops +8 Type mismatch: cannot convert from int to val +8 Type mismatch: cannot convert from String to val +8 Type mismatch: cannot convert from double to val
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/ValInvalidParameter.java.messages b/test/transform/resource/messages-ecj/ValInvalidParameter.java.messages new file mode 100644 index 00000000..cbf2d7c4 --- /dev/null +++ b/test/transform/resource/messages-ecj/ValInvalidParameter.java.messages @@ -0,0 +1,9 @@ +5 NonExistingClass cannot be resolved to a type +6 NonExistingClass cannot be resolved to a type +7 The method nonExisitingMethod(Integer) is undefined for the type ValInvalidParameter +8 nonExistingObject cannot be resolved +9 The method nonExistingMethod() is undefined for the type Integer +10 NonExistingClass cannot be resolved to a type +11 The method b2(int, int) in the type ValInvalidParameter is not applicable for the arguments (int) +12 The method a(String) is ambiguous for the type ValInvalidParameter +13 The method a(String) is ambiguous for the type ValInvalidParameter
\ No newline at end of file diff --git a/test/transform/resource/messages-idempotent/ValInvalidParameter.java.messages b/test/transform/resource/messages-idempotent/ValInvalidParameter.java.messages new file mode 100644 index 00000000..539d29cd --- /dev/null +++ b/test/transform/resource/messages-idempotent/ValInvalidParameter.java.messages @@ -0,0 +1,9 @@ +3 cannot find symbol +4 cannot find symbol +5 cannot find symbol +6 cannot find symbol +7 cannot find symbol +8 cannot find symbol +9 method b2 in class ValInvalidParameter cannot be applied to given types; +10 reference to a is ambiguous +11 reference to a is ambiguous
\ No newline at end of file diff --git a/test/transform/src/lombok/transform/TestSourceFiles.java b/test/transform/src/lombok/transform/TestSourceFiles.java index ac8b59c1..5fb0614b 100644 --- a/test/transform/src/lombok/transform/TestSourceFiles.java +++ b/test/transform/src/lombok/transform/TestSourceFiles.java @@ -51,7 +51,7 @@ public class TestSourceFiles extends DirectoryRunner.TestParams { @Override public File getMessagesDirectory() { - return null; + return new File("test/pretty/resource/messages"); } @Override diff --git a/website/templates/features/GetterSetter.html b/website/templates/features/GetterSetter.html index a429c9ac..8b16d34d 100644 --- a/website/templates/features/GetterSetter.html +++ b/website/templates/features/GetterSetter.html @@ -38,6 +38,11 @@ </dt><dd> If set to <code>true</code>, getters generated for <code>boolean</code> fields will use the <code>get</code> prefix instead of the default<code>is</code> prefix, and any generated code that calls getters, such as <code>@ToString</code>, will also use <code>get</code> instead of <code>is</code> </dd><dt> + <code>lombok.accessors.capitalization</code> = [<code>basic</code> | <code>beanspec</code>] (default: basic) + </dt><dd> + Controls how tricky cases like <code>uShaped</code> (one lowercase letter followed by an upper/titlecase letter) are capitalized. <code>basic</code> capitalizes that to <code>getUShaped</code>, and <code>beanspec</code> capitalizes that to <code>getuShaped</code> instead.<br /> + Both strategies are commonly used in the java ecosystem, though <code>beanspec</code> is more common. + </dd><dt> <code>lombok.setter.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) </dt><dd> Lombok will flag any usage of <code>@Setter</code> as a warning or error if configured. diff --git a/website/templates/features/Value.html b/website/templates/features/Value.html index c41b6b10..e128383f 100644 --- a/website/templates/features/Value.html +++ b/website/templates/features/Value.html @@ -5,7 +5,7 @@ <p> <code>@Value</code> was introduced as experimental feature in lombok v0.11.4. </p><p> - <code>@Value</code> no longer implies <code>@Wither</code> since lombok v0.11.8. + <code>@Value</code> no longer implies <code>@With</code> since lombok v0.11.8. </p><p> <code>@Value</code> promoted to the main <code>lombok</code> package since lombok v0.12.0. </p> diff --git a/website/templates/features/With.html b/website/templates/features/With.html index 8b34f038..867c17eb 100644 --- a/website/templates/features/With.html +++ b/website/templates/features/With.html @@ -27,6 +27,15 @@ <@f.snippets name="With" /> <@f.confKeys> + <><dt> + <code>lombok.accessors.prefix</code> += <em>a field prefix</em> (default: empty list) + </dt><dd> + This is a list property; entries can be added with the <code>+=</code> operator. Inherited prefixes from parent config files can be removed with the <code>-=</code> operator. Lombok will strip any matching field prefix from the name of a field in order to determine the name of the getter/setter to generate. For example, if <code>m</code> is one of the prefixes listed in this setting, then a field named <code>mFoobar</code> will result in a getter named <code>getFoobar()</code>, not <code>getMFoobar()</code>. An explicitly configured <code>prefix</code> parameter of an <a href="/features/experimental/Accessors"><code>@Accessors</code></a> annotation takes precedence over this setting. + </dd><dt> + <code>lombok.accessors.capitalization</code> = [<code>basic</code> | <code>beanspec</code>] (default: basic) + </dt><dd> + Controls how tricky cases like <code>uShaped</code> (one lowercase letter followed by an upper/titlecase letter) are capitalized. <code>basic</code> capitalizes that to <code>withUShaped</code>, and <code>beanspec</code> capitalizes that to <code>withuShaped</code> instead.<br /> + Both strategies are commonly used in the java ecosystem, though <code>beanspec</code> is more common. <dt> <code>lombok.with.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) </dt><dd> diff --git a/website/templates/features/experimental/Accessors.html b/website/templates/features/experimental/Accessors.html index 564ab66d..9a9385cb 100644 --- a/website/templates/features/experimental/Accessors.html +++ b/website/templates/features/experimental/Accessors.html @@ -4,9 +4,11 @@ <@f.history> <p> <code>@Accessors</code> was introduced as experimental feature in lombok v0.11.0. + </p><p> + The <em>lombok.config</em> option <code>lombok.accessors.capitalization</code> = [<code>basic</code> | <code>beanspec</code>] was added in lombok v1.18.24. </p> </@f.history> - + <@f.experimental> <ul> <li> @@ -17,7 +19,6 @@ </ul> Current status: <em>neutral</em> - Some changes are expected. These changes are intended to be backwards compatible, but should start in an experimental feature: <ul> - <li>Open feature request: naming behaviour for properties that start with a lowercase letter followed by an uppercase letter. Half of specs, tools and lombok users prefer that a field named <code>uLimit</code> into <code>getULimit</code> (including lombok) and the other half turn prefer <code>getuLimit</code>. <code>@Accessors</code> may be involved in any update that addresses this <a href="https://github.com/projectlombok/lombok/issues/2693">request</a>.</li> <li>Open feature request: More control over naming accessors; for example to address creatively named boolean properties: Turn <code>boolean wasRunning</code> into <code>boolean wasRunning()</code> instead of <code>boolean isWasRunning()</code>, as well as more expansive prefix support. <code>@Accessors</code> will be involved if this feature <a href="https://github.com/projectlombok/lombok/issues/2464">request</a> is addressed.</li> <li><code>@Accessors</code> currently does not 'cascade' from field <code>@Accessors</code> annotation to the class-level <code>@Accessors</code> annotation, but it does 'cascade' to <code>lombok.config</code>. Changing this is not difficult but backwards incompatible. It's not likely to break much existing code, but this needs to be decided on before the feature can move out of <em>experimental</em> status.</li> </ul> @@ -44,7 +45,7 @@ </li> </ul> <p><p> - The <code>@Accessors</code> annotation is legal on types and fields; the annotation that applies is the one on the field if present, otherwise the one on the class. When a <code>@Accessors</code> annotation on a field is present, any <code>@Accessors</code> annotation also present on the class the field is in, is entirely ignored, <em>even for properties not configured on the field <code>@Accessors</code></em>. This in contrast to any <code>lombok.config</code> configuration keys which serve as fall-back default if any explicit <code>@Accessors</code> annotation doesn't specify. + The <code>@Accessors</code> annotation is legal on types and fields; the annotation that applies is the one on the field if present, otherwise the one on the class. When an <code>@Accessors</code> annotation on a field is present, any <code>@Accessors</code> annotation also present on the class the field is in, is entirely ignored, <em>even for properties not configured on the field <code>@Accessors</code></em>. This in contrast to any <code>lombok.config</code> configuration keys which serve as fall-back default if any explicit <code>@Accessors</code> annotation doesn't specify. </p> </@f.overview> @@ -64,6 +65,11 @@ </dt><dd> This is a list property; entries can be added with the <code>+=</code> operator. Inherited prefixes from parent config files can be removed with the <code>-=</code> operator. Any class that either doesn't have an <code>@Accessors</code> annotation, or it does, but that annotation does not have an explicit value for the <code>prefix</code> parameter, will act as if <code>@Accessors(prefix = {<em>prefixes listed in configuration</em>})</code> is present. </dd><dt> + <code>lombok.accessors.capitalization</code> = [<code>basic</code> | <code>beanspec</code>] (default: basic) + </dt><dd> + Controls how tricky cases like <code>uShaped</code> (one lowercase letter followed by an upper/titlecase letter) are capitalized. <code>basic</code> capitalizes that to <code>getUShaped</code>, and <code>beanspec</code> capitalizes that to <code>getuShaped</code> instead.<br /> + Both strategies are commonly used in the java ecosystem, though <code>beanspec</code> is more common. + </dd><dt> <code>lombok.accessors.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) </dt><dd> Lombok will flag any usage of <code>@Accessors</code> as a warning or error if configured. diff --git a/website/templates/features/experimental/FieldNameConstants.html b/website/templates/features/experimental/FieldNameConstants.html index e88b7670..06fa23b5 100644 --- a/website/templates/features/experimental/FieldNameConstants.html +++ b/website/templates/features/experimental/FieldNameConstants.html @@ -24,7 +24,7 @@ <p> The <code>@FieldNameConstants</code> annotation generates an inner type which contains 1 constant for each field in your class; either string constants (fields marked <code>public static final</code>, of type <code>java.lang.String</code>) or if you prefer, an enum type with 1 value for each field - write <code>@FieldNameConstants(asEnum = true)</code> for the enum variant. <code>@FieldNameConstants</code> is useful for various marshalling and serialization frameworks. The constant field (whether enum value or string constant) always has the exact same name as the field, capitalization and all, unless you set the <code>lombok.fieldNameConstants.uppercase = true</code> option in your <code>lombok.config</code> file; in that case lombok will try to <code>UPPER_CASE</code> the name. </p><p> - The generated inner type is by default called <code>Fields</code> and is <code>public</code>. You can modify this via <code>@FieldNameConstants(innerTypeName = "FieldNames", access = AccessLevel.PACKAGE)</code> for example. The default inner type name can also be modified via configuration key <code>lombok.fieldNameConstants.innerTypeName</code>. The generated fields are always <code>public</code>. + The generated inner type is by default called <code>Fields</code> and is <code>public</code>. You can modify this via <code>@FieldNameConstants(innerTypeName = "FieldNames", level = AccessLevel.PACKAGE)</code> for example. The default inner type name can also be modified via configuration key <code>lombok.fieldNameConstants.innerTypeName</code>. The generated fields are always <code>public</code>. </p><p> Must be applied to classes (or enums, though you'd rarely want to do that). By default includes all non-transient, non-static fields. You can use <code>@FieldNameConstants.Include</code> in fields + <code>@FieldNameConstants(onlyExplicitlyIncluded = true)</code>, or <code>@FieldNameConstants.Exclude</code> for more fine-grained control. </p> diff --git a/website/templates/features/val.html b/website/templates/features/val.html index 32a8ffdf..1b137c65 100644 --- a/website/templates/features/val.html +++ b/website/templates/features/val.html @@ -5,6 +5,9 @@ <p> <code>val</code> was introduced in lombok 0.10. </p> + <p> + <em>NEW in Lombok 1.18.22: </em><code>val</code> gets replaced with <code>final var</code>. + </p> </@f.history> <@f.overview> <p> diff --git a/website/usageExamples/ValueExample_pre.jpage b/website/usageExamples/ValueExample_pre.jpage index d9550c25..27b28eb7 100644 --- a/website/usageExamples/ValueExample_pre.jpage +++ b/website/usageExamples/ValueExample_pre.jpage @@ -1,12 +1,12 @@ import lombok.AccessLevel; import lombok.experimental.NonFinal; import lombok.experimental.Value; -import lombok.experimental.Wither; +import lombok.experimental.With; import lombok.ToString; @Value public class ValueExample { String name; - @Wither(AccessLevel.PACKAGE) @NonFinal int age; + @With(AccessLevel.PACKAGE) @NonFinal int age; double score; protected String[] tags; |