diff options
Diffstat (limited to 'src')
48 files changed, 570 insertions, 218 deletions
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 { |