From 0375f1a9e8f606588d4e136fc718a6876ff0ae4f Mon Sep 17 00:00:00 2001 From: Thomas Klambauer Date: Tue, 17 Jul 2018 13:35:34 +0200 Subject: lombok config broken: version must be string otherwise gradle compile will fail. --- website/templates/setup/gradle.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/templates/setup/gradle.html b/website/templates/setup/gradle.html index 7cb4af0d..41d90dcc 100644 --- a/website/templates/setup/gradle.html +++ b/website/templates/setup/gradle.html @@ -15,7 +15,7 @@

Note, to tell the gradle-lombok plugin to use the latest version of lombok, you need to explicitly tell it about the latest version number and the SHA-256. For our current latest version, put this in your build.gradle file:

 lombok {
-	version = ${version} 
+	version = '${version}'
 	sha256 = ""
 }

-- cgit From a195a47337f592eb117f519f7a1a42f0d8f570d1 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 17 Jul 2018 22:32:24 +0200 Subject: Attempting to fix issues with integration with mapstruct; issue #1359 --- build.xml | 3 ++- doc/changelog.markdown | 1 + src/launch/lombok/launch/ShadowClassLoader.java | 9 +++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/build.xml b/build.xml index 28c7fd75..c1d13bd7 100644 --- a/build.xml +++ b/build.xml @@ -261,7 +261,8 @@ the common tasks and can be called on to run the main aspects of all the sub-scr - + + diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 8166f3d1..a77dbb3d 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,6 +2,7 @@ Lombok Changelog ---------------- ### v1.18.1 "Edgy Guinea Pig" +* BUGFIX: mapstruct + lombok in eclipse should hopefully work again. [Issue #1359](https://github.com/rzwitserloot/lombok/issues/1359) and [mapstruct issue #1159](https://github.com/mapstruct/mapstruct/issues/1159) * BUGFIX: Equals and hashCode again exclude transient fields by default. [Issue #1724](https://github.com/rzwitserloot/lombok/issues/1724) * FEATURE: You can now make builders for type hierarchies, using the new (experimental) `@SuperBuilder` annotation. Thanks for the contribution, Jan Rieke. [`@SuperBuilder` documentation](https://projectlombok.org/features/experimental/SuperBuilder) * FEATURE: `@NoArgsConstructor`, including forcing one with `lombok.config: lombok.noArgsConstructor.extraPrivate=true` now take any defaults set with `@Builder.Default` into account. [Issue #1347](https://github.com/rzwitserloot/lombok/issues/1347) diff --git a/src/launch/lombok/launch/ShadowClassLoader.java b/src/launch/lombok/launch/ShadowClassLoader.java index 36dd289c..32363469 100644 --- a/src/launch/lombok/launch/ShadowClassLoader.java +++ b/src/launch/lombok/launch/ShadowClassLoader.java @@ -526,9 +526,14 @@ class ShadowClassLoader extends ClassLoader { String fileNameOfClass = name.replace(".", "/") + ".class"; URL res = getResource_(fileNameOfClass, true); if (res == null) { - if (!exclusionListMatch(fileNameOfClass)) return super.loadClass(name, resolve); - throw new ClassNotFoundException(name); + if (!exclusionListMatch(fileNameOfClass)) try { + return super.loadClass(name, resolve); + } catch (ClassNotFoundException cnfe) { + res = getResource_("secondaryLoading.SCL." + sclSuffix + "/" + name.replace(".", "/") + ".SCL." + sclSuffix, true); + if (res == null) throw cnfe; + } } + if (res == null) throw new ClassNotFoundException(name); byte[] b; int p = 0; -- cgit From ff739d6d5a6a68f8d87480be7b0c0104e08f77e0 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 19 Jul 2018 21:46:39 +0200 Subject: Add Roland Praml to authors list --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 0e542693..5246fde7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -23,6 +23,7 @@ Rabea Gransberger Reinier Zwitserloot Robbert Jan Grootjans Roel Spilker +Roland Praml Sander Koning Szymon Pacanowski Taiki Sugawara -- cgit From be1cfd2f59933725726ec5810e0c189a4aca6ad7 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Sun, 8 Jul 2018 16:52:14 +0200 Subject: Replaced StringBuilder by simple char array in "hotspot" method --- src/core/lombok/bytecode/ClassFileMetaData.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/lombok/bytecode/ClassFileMetaData.java b/src/core/lombok/bytecode/ClassFileMetaData.java index 0dc6a6c8..826eed83 100644 --- a/src/core/lombok/bytecode/ClassFileMetaData.java +++ b/src/core/lombok/bytecode/ClassFileMetaData.java @@ -116,23 +116,24 @@ public class ClassFileMetaData { int end = pos + size; // the resulting string might be smaller - StringBuilder result = new StringBuilder(size); + char[] result = new char[size]; + int length = 0; while (pos < end) { int first = (byteCode[pos++] & 0xFF); if (first < 0x80) { - result.append((char)first); + result[length++] = (char)first; } else if ((first & 0xE0) == 0xC0) { int x = (first & 0x1F) << 6; int y = (byteCode[pos++] & 0x3F); - result.append((char)(x | y)); + result[length++] = (char)(x | y); } else { int x = (first & 0x0F) << 12; int y = (byteCode[pos++] & 0x3F) << 6; int z = (byteCode[pos++] & 0x3F); - result.append((char)(x | y | z)); + result[length++] = (char)(x | y | z); } } - return result.toString(); + return new String(result, 0, length); } /** -- cgit From 111d0a5f16667824d0a73b733624e6deffe19a0e Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 21:10:20 +0200 Subject: Fixes issue #1789 - picking another workspace duplicates the ‘lombok is installed’ text in the eclipse about dialog. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java index 52f63765..c0a2c6fe 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java @@ -32,6 +32,7 @@ import lombok.core.Version; public class PatchFixesShadowLoaded { public static String addLombokNotesToEclipseAboutDialog(String origReturnValue, String key) { if ("aboutText".equals(key)) { + if (origReturnValue.contains(" is installed. https://projectlombok.org")) return origReturnValue; return origReturnValue + "\n\nLombok " + Version.getFullVersion() + " is installed. https://projectlombok.org/"; } return origReturnValue; -- cgit From 5ec61bb62d3dd2d9509ade090e750dd43e36c0f3 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 21:41:17 +0200 Subject: [fixes issue #1759] We removed the ‘flag usage’ check on builder instead of replacing it with the non-experimental check about 3 years ago when builder moved out of experimental. The check has now been restored. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/lombok/javac/handlers/HandleBuilder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index bb495fbc..f04ea8b1 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -99,6 +99,8 @@ public class HandleBuilder extends JavacAnnotationHandler { } @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder"); + Builder builderInstance = annotation.getInstance(); // These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them. -- cgit From 7c3724c9dc03684b9e4ecb9b33296c894138add6 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 22:04:52 +0200 Subject: [Fixes issue #1783] lombok.var / lombok.experimental.var import would be removed by eclipse’s organize imports. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/changelog.markdown | 1 + .../lombok/eclipse/agent/PatchVal.java | 16 ++--- .../lombok/eclipse/agent/PatchValEclipse.java | 84 ++++++++++++++++------ 3 files changed, 70 insertions(+), 31 deletions(-) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index a77dbb3d..e6392c53 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -4,6 +4,7 @@ Lombok Changelog ### v1.18.1 "Edgy Guinea Pig" * BUGFIX: mapstruct + lombok in eclipse should hopefully work again. [Issue #1359](https://github.com/rzwitserloot/lombok/issues/1359) and [mapstruct issue #1159](https://github.com/mapstruct/mapstruct/issues/1159) * BUGFIX: Equals and hashCode again exclude transient fields by default. [Issue #1724](https://github.com/rzwitserloot/lombok/issues/1724) +* BUGFIX: Eclipse 'organize imports' feature (either explicitly, or if automatically triggered on saving via 'save actions') would remove the import for `lombok.var`. [Issue #1783](https://github.com/rzwitserloot/lombok/issues/1783) * FEATURE: You can now make builders for type hierarchies, using the new (experimental) `@SuperBuilder` annotation. Thanks for the contribution, Jan Rieke. [`@SuperBuilder` documentation](https://projectlombok.org/features/experimental/SuperBuilder) * FEATURE: `@NoArgsConstructor`, including forcing one with `lombok.config: lombok.noArgsConstructor.extraPrivate=true` now take any defaults set with `@Builder.Default` into account. [Issue #1347](https://github.com/rzwitserloot/lombok/issues/1347) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index c2a362bd..fee104d3 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -210,16 +210,16 @@ public class PatchVal { if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false; boolean decomponent = false; - boolean val = isVal(local, scope); - boolean var = isVar(local, scope); - if (!(val || var)) return false; + boolean val = isVal(local, scope); + boolean var = isVar(local, scope); + if (!(val || var)) return false; StackTraceElement[] st = new Throwable().getStackTrace(); for (int i = 0; i < st.length - 2 && i < 10; i++) { if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) { boolean valInForStatement = val && - st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && - st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement"); + st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && + st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement"); if (valInForStatement) return false; break; } @@ -269,7 +269,7 @@ public class PatchVal { } } - if(val) local.modifiers |= ClassFileConstants.AccFinal; + if (val) local.modifiers |= ClassFileConstants.AccFinal; local.annotations = addValAnnotation(local.annotations, local.type, scope); local.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(local.type, 3)); @@ -298,7 +298,7 @@ public class PatchVal { if (val) forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; forEach.elementVariable.annotations = addValAnnotation(forEach.elementVariable.annotations, forEach.elementVariable.type, scope); forEach.elementVariable.type = replacement != null ? replacement : - new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3)); + new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3)); return false; } @@ -326,7 +326,7 @@ public class PatchVal { resolved = ((ArrayBinding) resolved).elementsType(); return resolved; } else if (resolved instanceof ReferenceBinding) { - ReferenceBinding iterableType = ((ReferenceBinding)resolved).findSuperTypeOriginatingFrom(TypeIds.T_JavaLangIterable, false); + ReferenceBinding iterableType = ((ReferenceBinding) resolved).findSuperTypeOriginatingFrom(TypeIds.T_JavaLangIterable, false); TypeBinding[] arguments = null; if (iterableType != null) switch (iterableType.kind()) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index d59b6a2e..99447bae 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -47,9 +47,9 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.parser.Parser; public class PatchValEclipse { @@ -103,6 +103,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVal(ImportReference[] imports, TypeReference type) { + return PatchVal.couldBe(imports, "lombok.val", type); + } + private static boolean couldBeVar(ImportReference[] imports, TypeReference type) { return PatchVal.couldBe(imports, "lombok.experimental.var", type) || PatchVal.couldBe(imports, "lombok.var", type); } @@ -118,17 +122,18 @@ public class PatchValEclipse { } public static void addFinalAndValAnnotationToModifierList(Object converter, List modifiers, AST ast, LocalDeclaration in) { - // First check that 'in' has the final flag on, and a @val / @lombok.val annotation. - if ((in.modifiers & ClassFileConstants.AccFinal) == 0) return; + // First check that 'in' has the final flag on, and a @val / @lombok.val / @var / @lombok.var annotation. if (in.annotations == null) return; boolean found = false; - Annotation valAnnotation = null; - + Annotation valAnnotation = null, varAnnotation = null; for (Annotation ann : in.annotations) { if (couldBeVal(null, ann.type)) { found = true; valAnnotation = ann; - break; + } + if (couldBeVar(null, ann.type)) { + found = true; + varAnnotation = ann; } } @@ -139,10 +144,11 @@ public class PatchValEclipse { if (modifiers == null) return; // This is null only if the project is 1.4 or less. Lombok doesn't work in that. boolean finalIsPresent = false; boolean valIsPresent = false; + boolean varIsPresent = false; for (Object present : modifiers) { if (present instanceof Modifier) { - ModifierKeyword keyword = ((Modifier)present).getKeyword(); + ModifierKeyword keyword = ((Modifier) present).getKeyword(); if (keyword == null) continue; if (keyword.toFlagValue() == Modifier.FINAL) finalIsPresent = true; } @@ -151,20 +157,18 @@ public class PatchValEclipse { Name typeName = ((org.eclipse.jdt.core.dom.Annotation) present).getTypeName(); if (typeName != null) { String fullyQualifiedName = typeName.getFullyQualifiedName(); - if ("val".equals(fullyQualifiedName) || "lombok.val".equals(fullyQualifiedName)) { - valIsPresent = true; - } + if ("val".equals(fullyQualifiedName) || "lombok.val".equals(fullyQualifiedName)) valIsPresent = true; + if ("var".equals(fullyQualifiedName) || "lombok.var".equals(fullyQualifiedName) || "lombok.experimental.var".equals(fullyQualifiedName)) varIsPresent = true; } } } - if (!finalIsPresent) { - modifiers.add( - createModifier(ast, ModifierKeyword.FINAL_KEYWORD, valAnnotation.sourceStart, valAnnotation.sourceEnd)); + if (!finalIsPresent && valAnnotation != null) { + modifiers.add(createModifier(ast, ModifierKeyword.FINAL_KEYWORD, valAnnotation.sourceStart, valAnnotation.sourceEnd)); } - if (!valIsPresent) { - MarkerAnnotation newAnnotation = createValAnnotation(ast, valAnnotation, valAnnotation.sourceStart, valAnnotation.sourceEnd); + if (!valIsPresent && valAnnotation != null) { + MarkerAnnotation newAnnotation = createValVarAnnotation(ast, valAnnotation, valAnnotation.sourceStart, valAnnotation.sourceEnd); try { Reflection.astConverterRecordNodes.invoke(converter, newAnnotation, valAnnotation); Reflection.astConverterRecordNodes.invoke(converter, newAnnotation.getTypeName(), valAnnotation.type); @@ -175,10 +179,19 @@ public class PatchValEclipse { } modifiers.add(newAnnotation); } - } - - private static boolean couldBeVal(ImportReference[] imports, TypeReference type) { - return PatchVal.couldBe(imports, "lombok.val", type); + + if (!varIsPresent && varAnnotation != null) { + MarkerAnnotation newAnnotation = createValVarAnnotation(ast, varAnnotation, varAnnotation.sourceStart, varAnnotation.sourceEnd); + try { + Reflection.astConverterRecordNodes.invoke(converter, newAnnotation, varAnnotation); + Reflection.astConverterRecordNodes.invoke(converter, newAnnotation.getTypeName(), varAnnotation.type); + } catch (IllegalAccessException e) { + throw Lombok.sneakyThrow(e); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); + } + modifiers.add(newAnnotation); + } } public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) { @@ -200,7 +213,7 @@ public class PatchValEclipse { return modifier; } - public static MarkerAnnotation createValAnnotation(AST ast, Annotation original, int start, int end) { + public static MarkerAnnotation createValVarAnnotation(AST ast, Annotation original, int start, int end) { MarkerAnnotation out = null; try { out = Reflection.markerAnnotationConstructor.newInstance(ast); @@ -212,13 +225,23 @@ public class PatchValEclipse { throw Lombok.sneakyThrow(e); } + char[][] tokens; + if (original.type instanceof SingleTypeReference) { + tokens = new char[1][]; + tokens[0] = ((SingleTypeReference) original.type).token; + } else if (original.type instanceof QualifiedTypeReference) { + tokens = ((QualifiedTypeReference) original.type).tokens; + } else { + return null; + } + if (out != null) { - SimpleName valName = ast.newSimpleName("val"); + SimpleName valName = ast.newSimpleName(new String(tokens[tokens.length - 1])); valName.setSourceRange(start, end - start + 1); - if (original.type instanceof SingleTypeReference) { + if (tokens.length == 1) { out.setTypeName(valName); setIndex(valName, 1); - } else { + } else if (tokens.length == 2) { SimpleName lombokName = ast.newSimpleName("lombok"); lombokName.setSourceRange(start, end - start + 1); setIndex(lombokName, 1); @@ -227,6 +250,21 @@ public class PatchValEclipse { setIndex(fullName, 1); fullName.setSourceRange(start, end - start + 1); out.setTypeName(fullName); + } else { + SimpleName lombokName = ast.newSimpleName("lombok"); + lombokName.setSourceRange(start, end - start + 1); + SimpleName experimentalName = ast.newSimpleName("experimental"); + lombokName.setSourceRange(start, end - start + 1); + setIndex(lombokName, 1); + setIndex(experimentalName, 2); + setIndex(valName, 3); + QualifiedName lombokExperimentalName = ast.newQualifiedName(lombokName, experimentalName); + lombokExperimentalName.setSourceRange(start, end - start + 1); + setIndex(lombokExperimentalName, 1); + QualifiedName fullName = ast.newQualifiedName(lombokExperimentalName, valName); + setIndex(fullName, 1); + fullName.setSourceRange(start, end - start + 1); + out.setTypeName(fullName); } out.setSourceRange(start, end - start + 1); } -- cgit From 7e94041dbc177476020969b00d3411020418f903 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 23:19:00 +0200 Subject: Added key ‘dangerousconfig.lombok.disable’. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/lombok/ConfigurationKeys.java | 9 ++++++++- src/core/lombok/core/LombokConfiguration.java | 15 ++++++++++----- src/core/lombok/core/configuration/ConfigurationApp.java | 7 ++++--- src/core/lombok/core/configuration/ConfigurationKey.java | 12 +++++++++++- .../core/configuration/ConfigurationResolverFactory.java | 6 +++--- src/core/lombok/eclipse/EclipseAST.java | 12 ++++++++---- src/core/lombok/eclipse/TransformEclipseAST.java | 6 +++++- src/core/lombok/javac/JavacAST.java | 7 +++++-- src/core/lombok/javac/JavacTransformer.java | 11 +++++++++-- test/core/src/lombok/AbstractRunTests.java | 6 +++--- 10 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index f5134bbd..1a28c0fa 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2017 The Project Lombok Authors. + * Copyright (C) 2013-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,6 +38,13 @@ public class ConfigurationKeys { // ----- global ----- + /** + * lombok configuration: {@code dangerousconfig.lombok.disable} = {@code true} | {@code false}. + * + * If {@code true}, lombok is disabled entirely. + */ + public static final ConfigurationKey LOMBOK_DISABLE = new ConfigurationKey("dangerousconfig.lombok.disable", "Disables lombok transformers. It does not flag any lombok mentions (so, @Cleanup silently does nothing), and does not disable patched operations in eclipse either. Don't use this unless you know what you're doing. (default: false).", true) {}; + /** * lombok configuration: {@code lombok.addGeneratedAnnotation} = {@code true} | {@code false}. * diff --git a/src/core/lombok/core/LombokConfiguration.java b/src/core/lombok/core/LombokConfiguration.java index eb7b3d75..4a79c797 100644 --- a/src/core/lombok/core/LombokConfiguration.java +++ b/src/core/lombok/core/LombokConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 The Project Lombok Authors. + * Copyright (C) 2013-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,7 @@ */ package lombok.core; +import java.net.URI; import java.util.Collections; import lombok.core.configuration.BubblingConfigurationResolver; @@ -44,7 +45,7 @@ public class LombokConfiguration { static { if (System.getProperty("lombok.disableConfig") != null) { configurationResolverFactory = new ConfigurationResolverFactory() { - @Override public ConfigurationResolver createResolver(AST ast) { + @Override public ConfigurationResolver createResolver(URI sourceLocation) { return NULL_RESOLVER; } }; @@ -63,13 +64,17 @@ public class LombokConfiguration { } static T read(ConfigurationKey key, AST ast) { - return configurationResolverFactory.createResolver(ast).resolve(key); + return configurationResolverFactory.createResolver(ast.getAbsoluteFileLocation()).resolve(key); + } + + public static T read(ConfigurationKey key, URI sourceLocation) { + return configurationResolverFactory.createResolver(sourceLocation).resolve(key); } private static ConfigurationResolverFactory createFileSystemBubblingResolverFactory() { return new ConfigurationResolverFactory() { - @Override public ConfigurationResolver createResolver(AST ast) { - return new BubblingConfigurationResolver(cache.sourcesForJavaFile(ast.getAbsoluteFileLocation(), ConfigurationProblemReporter.CONSOLE)); + @Override public ConfigurationResolver createResolver(URI sourceLocation) { + return new BubblingConfigurationResolver(cache.sourcesForJavaFile(sourceLocation, ConfigurationProblemReporter.CONSOLE)); } }; } diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java index efe57e38..9cfec2e7 100644 --- a/src/core/lombok/core/configuration/ConfigurationApp.java +++ b/src/core/lombok/core/configuration/ConfigurationApp.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -118,7 +118,7 @@ public class ConfigurationApp extends LombokApp { boolean verbose = args.verbose; if (args.generate) { - return generate(keys, verbose); + return generate(keys, verbose, !args.key.isEmpty()); } return display(keys, verbose, args.paths, !args.key.isEmpty()); @@ -130,8 +130,9 @@ public class ConfigurationApp extends LombokApp { return this; } - public int generate(Collection> keys, boolean verbose) { + public int generate(Collection> keys, boolean verbose, boolean explicit) { for (ConfigurationKey key : keys) { + if (!explicit && key.isHidden()) continue; String keyName = key.getKeyName(); ConfigurationDataType type = key.getType(); String description = key.getDescription(); diff --git a/src/core/lombok/core/configuration/ConfigurationKey.java b/src/core/lombok/core/configuration/ConfigurationKey.java index d46a70b0..18075190 100644 --- a/src/core/lombok/core/configuration/ConfigurationKey.java +++ b/src/core/lombok/core/configuration/ConfigurationKey.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 The Project Lombok Authors. + * Copyright (C) 2013-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,13 +43,19 @@ public abstract class ConfigurationKey { private final String keyName; private final String description; private final ConfigurationDataType type; + private final boolean hidden; public ConfigurationKey(String keyName, String description) { + this(keyName, description, false); + } + + public ConfigurationKey(String keyName, String description, boolean hidden) { this.keyName = checkName(keyName); @SuppressWarnings("unchecked") ConfigurationDataType type = ConfigurationDataType.toDataType((Class>)getClass()); this.type = type; this.description = description; + this.hidden = hidden; registerKey(keyName, this); } @@ -65,6 +71,10 @@ public abstract class ConfigurationKey { return type; } + public final boolean isHidden() { + return hidden; + } + @Override public String toString() { return keyName + " (" + type + "): " + description; } diff --git a/src/core/lombok/core/configuration/ConfigurationResolverFactory.java b/src/core/lombok/core/configuration/ConfigurationResolverFactory.java index 83b58c2f..b640b271 100644 --- a/src/core/lombok/core/configuration/ConfigurationResolverFactory.java +++ b/src/core/lombok/core/configuration/ConfigurationResolverFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,8 +21,8 @@ */ package lombok.core.configuration; -import lombok.core.AST; +import java.net.URI; public interface ConfigurationResolverFactory { - ConfigurationResolver createResolver(AST ast); + ConfigurationResolver createResolver(URI sourceLocation); } diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index dc2c9843..7cd2e400 100644 --- a/src/core/lombok/eclipse/EclipseAST.java +++ b/src/core/lombok/eclipse/EclipseAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2013 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -73,16 +73,20 @@ public class EclipseAST extends AST { private static final URI NOT_CALCULATED_MARKER = URI.create("https://projectlombok.org/not/calculated"); private URI memoizedAbsoluteFileLocation = NOT_CALCULATED_MARKER; + public static URI getAbsoluteFileLocation(CompilationUnitDeclaration ast) { + return getAbsoluteFileLocation0(ast); + } + public URI getAbsoluteFileLocation() { if (memoizedAbsoluteFileLocation != NOT_CALCULATED_MARKER) return memoizedAbsoluteFileLocation; - memoizedAbsoluteFileLocation = getAbsoluteFileLocation0(); + memoizedAbsoluteFileLocation = getAbsoluteFileLocation0(this.compilationUnitDeclaration); return memoizedAbsoluteFileLocation; } /** This is the call, but we wrapped it to memoize this. */ - private URI getAbsoluteFileLocation0() { - String fileName = getFileName(); + private static URI getAbsoluteFileLocation0(CompilationUnitDeclaration ast) { + String fileName = toFileName(ast); if (fileName != null && (fileName.startsWith("file:") || fileName.startsWith("sourcecontrol:"))) { // Some exotic build systems get real fancy with filenames. Known culprits: // The 'jazz' source control system _probably_ (not confirmed yet) uses sourcecontrol://jazz: urls. diff --git a/src/core/lombok/eclipse/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java index 683465c9..541924ad 100644 --- a/src/core/lombok/eclipse/TransformEclipseAST.java +++ b/src/core/lombok/eclipse/TransformEclipseAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,8 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Field; +import lombok.ConfigurationKeys; +import lombok.core.LombokConfiguration; import lombok.core.debug.DebugSnapshotStore; import lombok.core.debug.HistogramTracker; import lombok.patcher.Symbols; @@ -143,6 +145,8 @@ public class TransformEclipseAST { // Do NOT abort if (ast.bits & ASTNode.HasAllMethodBodies) != 0 - that doesn't work. + if (Boolean.TRUE.equals(LombokConfiguration.read(ConfigurationKeys.LOMBOK_DISABLE, EclipseAST.getAbsoluteFileLocation(ast)))) return; + try { DebugSnapshotStore.INSTANCE.snapshot(ast, "transform entry"); long histoToken = lombokTracker == null ? 0L : lombokTracker.start(); diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 4ca2c050..091612cc 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -93,8 +93,11 @@ public class JavacAST extends AST { } @Override public URI getAbsoluteFileLocation() { + return getAbsoluteFileLocation((JCCompilationUnit) top().get()); + } + + public static URI getAbsoluteFileLocation(JCCompilationUnit cu) { try { - JCCompilationUnit cu = (JCCompilationUnit) top().get(); return cu.sourcefile.toUri(); } catch (Exception e) { return null; diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java index 54977a59..2e37b32b 100644 --- a/src/core/lombok/javac/JavacTransformer.java +++ b/src/core/lombok/javac/JavacTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,6 +35,9 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; +import lombok.ConfigurationKeys; +import lombok.core.LombokConfiguration; + public class JavacTransformer { private final HandlerLibrary handlers; private final Messager messager; @@ -65,7 +68,11 @@ public class JavacTransformer { java.util.List asts = new ArrayList(); - for (JCCompilationUnit unit : compilationUnits) asts.add(new JavacAST(messager, context, unit)); + for (JCCompilationUnit unit : compilationUnits) { + if (!Boolean.TRUE.equals(LombokConfiguration.read(ConfigurationKeys.LOMBOK_DISABLE, JavacAST.getAbsoluteFileLocation(unit)))) { + asts.add(new JavacAST(messager, context, unit)); + } + } for (JavacAST ast : asts) { ast.traverse(new AnnotationVisitor(priority)); diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index 3d672bc4..f93fbe27 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.StringWriter; +import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -40,7 +41,6 @@ import java.util.Map; import org.junit.Assert; import lombok.DirectoryRunner.FileTester; -import lombok.core.AST; import lombok.core.LombokConfiguration; import lombok.core.LombokImmutableList; import lombok.core.configuration.ConfigurationKeysLoader; @@ -84,7 +84,7 @@ public abstract class AbstractRunTests { StringWriter writer = new StringWriter(); LombokConfiguration.overrideConfigurationResolverFactory(new ConfigurationResolverFactory() { - @Override public ConfigurationResolver createResolver(AST ast) { + @Override public ConfigurationResolver createResolver(URI sourceLocation) { return sourceDirectives_.getConfiguration(); } }); -- cgit From dc715da8b79bff32116ac477d0ac04875bd21167 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 26 Jul 2018 00:00:24 +0200 Subject: pre-release version bump --- doc/changelog.markdown | 3 ++- src/core/lombok/core/Version.java | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index e6392c53..29bd1cce 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,10 +1,11 @@ Lombok Changelog ---------------- -### v1.18.1 "Edgy Guinea Pig" +### v1.18.2 (July 26th, 2018) * BUGFIX: mapstruct + lombok in eclipse should hopefully work again. [Issue #1359](https://github.com/rzwitserloot/lombok/issues/1359) and [mapstruct issue #1159](https://github.com/mapstruct/mapstruct/issues/1159) * BUGFIX: Equals and hashCode again exclude transient fields by default. [Issue #1724](https://github.com/rzwitserloot/lombok/issues/1724) * BUGFIX: Eclipse 'organize imports' feature (either explicitly, or if automatically triggered on saving via 'save actions') would remove the import for `lombok.var`. [Issue #1783](https://github.com/rzwitserloot/lombok/issues/1783) +* BUGFIX: Lombok and gradle v4.9 didn't work together; that's been fixed. [Issue #1716](https://github.com/rzwitserloot/lombok/issues/1716) and [gradle-apt-plugin issue #87](https://github.com/tbroyer/gradle-apt-plugin/issues/87) * FEATURE: You can now make builders for type hierarchies, using the new (experimental) `@SuperBuilder` annotation. Thanks for the contribution, Jan Rieke. [`@SuperBuilder` documentation](https://projectlombok.org/features/experimental/SuperBuilder) * FEATURE: `@NoArgsConstructor`, including forcing one with `lombok.config: lombok.noArgsConstructor.extraPrivate=true` now take any defaults set with `@Builder.Default` into account. [Issue #1347](https://github.com/rzwitserloot/lombok/issues/1347) diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 70af48e0..7b19d00e 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,9 +30,9 @@ 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.1"; - private static final String RELEASE_NAME = "Edgy Guinea Pig"; -// private static final String RELEASE_NAME = "Envious Ferret"; + private static final String VERSION = "1.18.2"; +// private static final String RELEASE_NAME = "Edgy Guinea Pig"; + private static final String RELEASE_NAME = "Envious Ferret"; // Named version history: // Angry Butterfly -- cgit From 61fbd4a7f82180871e635a0ca80248e0cec02cf3 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 26 Jul 2018 00:17:09 +0200 Subject: post-release version bump --- doc/changelog.markdown | 3 +++ src/core/lombok/core/Version.java | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 29bd1cce..0a12cb2d 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,6 +1,9 @@ Lombok Changelog ---------------- +### v1.18.3 "Edgy Guinea Pig" +* No changes yet. + ### v1.18.2 (July 26th, 2018) * BUGFIX: mapstruct + lombok in eclipse should hopefully work again. [Issue #1359](https://github.com/rzwitserloot/lombok/issues/1359) and [mapstruct issue #1159](https://github.com/mapstruct/mapstruct/issues/1159) * BUGFIX: Equals and hashCode again exclude transient fields by default. [Issue #1724](https://github.com/rzwitserloot/lombok/issues/1724) diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 7b19d00e..4b119873 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,9 +30,9 @@ 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.2"; -// private static final String RELEASE_NAME = "Edgy Guinea Pig"; - private static final String RELEASE_NAME = "Envious Ferret"; + private static final String VERSION = "1.18.3"; + private static final String RELEASE_NAME = "Edgy Guinea Pig"; +// private static final String RELEASE_NAME = "Envious Ferret"; // Named version history: // Angry Butterfly -- cgit From 3d432c38d0cfeb36b8e7402eca56faaafcf7bac7 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 29 Jul 2018 16:37:21 +0200 Subject: code impl of FieldNameConstants rewrite + test updates for it --- src/core/lombok/ConfigurationKeys.java | 11 +- .../eclipse/handlers/HandleFieldNameConstants.java | 144 +++++++++++++-------- .../lombok/experimental/FieldNameConstants.java | 28 +++- .../javac/handlers/HandleFieldNameConstants.java | 129 ++++++++++-------- .../after-delombok/FieldNameConstantsBasic.java | 8 +- .../FieldNameConstantsConfigKeys.java | 7 +- .../after-delombok/FieldNameConstantsEnum.java | 10 ++ .../after-delombok/FieldNameConstantsWeird.java | 6 - .../after-ecj/FieldNameConstantsBasic.java | 18 ++- .../after-ecj/FieldNameConstantsConfigKeys.java | 13 +- .../resource/after-ecj/FieldNameConstantsEnum.java | 23 ++++ .../after-ecj/FieldNameConstantsWeird.java | 13 -- .../resource/before/FieldNameConstantsBasic.java | 4 +- .../before/FieldNameConstantsConfigKeys.java | 3 +- .../resource/before/FieldNameConstantsEnum.java | 13 ++ .../resource/before/FieldNameConstantsWeird.java | 12 -- .../FieldNameConstantsWeird.java.messages | 1 - .../FieldNameConstantsWeird.java.messages | 1 - 18 files changed, 270 insertions(+), 174 deletions(-) create mode 100644 test/transform/resource/after-delombok/FieldNameConstantsEnum.java delete mode 100644 test/transform/resource/after-delombok/FieldNameConstantsWeird.java create mode 100644 test/transform/resource/after-ecj/FieldNameConstantsEnum.java delete mode 100644 test/transform/resource/after-ecj/FieldNameConstantsWeird.java create mode 100644 test/transform/resource/before/FieldNameConstantsEnum.java delete mode 100644 test/transform/resource/before/FieldNameConstantsWeird.java delete mode 100644 test/transform/resource/messages-delombok/FieldNameConstantsWeird.java.messages delete mode 100644 test/transform/resource/messages-ecj/FieldNameConstantsWeird.java.messages diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 1a28c0fa..184ded27 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -529,18 +529,11 @@ public class ConfigurationKeys { public static final ConfigurationKey FIELD_NAME_CONSTANTS_FLAG_USAGE = new ConfigurationKey("lombok.fieldNameConstants.flagUsage", "Emit a warning or error if @FieldNameConstants is used.") {}; /** - * lombok configuration: {@code lombok.fieldNameConstants.prefix} = <String: aJavaIdentifierPrefix> (Default: {@code PREFIX_}). + * lombok configuration: {@code lombok.fieldNameConstants.innerTypeName} = <String: AValidJavaTypeName> (Default: {@code Fields}). * * The names of the constants generated by {@code @FieldNameConstants} will be prefixed with this value. */ - public static final ConfigurationKey FIELD_NAME_CONSTANTS_PREFIX = new ConfigurationKey("lombok.fieldNameConstants.prefix", "names of constants generated by @FieldNameConstants will be prefixed with this value. (default: 'PREFIX_').") {}; - - /** - * lombok configuration: {@code lombok.fieldNameConstants.suffix} = <String: aJavaIdentifierPrefix> (Default: nothing). - * - * The names of the constants generated by {@code @FieldNameConstants} will be suffixed with this value. - */ - public static final ConfigurationKey FIELD_NAME_CONSTANTS_SUFFIX = new ConfigurationKey("lombok.fieldNameConstants.suffix", "names of constants generated by @FieldNameConstants will be suffixed with this value. (default: nothing).") {}; + public static final ConfigurationKey FIELD_NAME_CONSTANTS_INNER_TYPE_NAME = new ConfigurationKey("lombok.fieldNameConstants.innerTypeName", "The default name of the inner type generated by @FieldNameConstants. (default: 'Fields').") {}; // ----- Wither ----- diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index c3a28f7f..15650490 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -24,32 +24,37 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import java.lang.reflect.Modifier; -import java.util.Collection; +import java.util.ArrayList; +import java.util.List; import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; -import lombok.core.handlers.HandlerUtil; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.FieldNameConstants; import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.Clinit; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.mangosdk.spi.ProviderFor; @ProviderFor(EclipseAnnotationHandler.class) public class HandleFieldNameConstants extends EclipseAnnotationHandler { - public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, String prefix, String suffix) { + public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, boolean asEnum, String innerTypeName, boolean onlyExplicit) { TypeDeclaration typeDecl = null; if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get(); @@ -57,22 +62,29 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler qualified = new ArrayList(); + for (EclipseNode field : typeNode.down()) { - if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix); + if (fieldQualifiesForFieldNameConstantsGeneration(field, onlyExplicit)) qualified.add(field); + } + + if (qualified.isEmpty()) { + errorNode.addWarning("No fields qualify for @FieldNameConstants, therefore this annotation does nothing"); + } else { + createInnerTypeFieldNameConstants(typeNode, errorNode.get(), level, qualified, asEnum, innerTypeName); } } - private void generateFieldNameConstantsForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, String prefix, String suffix) { - if (hasAnnotation(FieldNameConstants.class, fieldNode)) return; - createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, pos, false); - } - - private boolean fieldQualifiesForFieldNameConstantsGeneration(EclipseNode field) { + private boolean fieldQualifiesForFieldNameConstantsGeneration(EclipseNode field, boolean onlyExplicit) { if (field.getKind() != Kind.FIELD) return false; + if (hasAnnotation(FieldNameConstants.Exclude.class, field)) return false; + if (hasAnnotation(FieldNameConstants.Include.class, field)) return true; + if (onlyExplicit) return false; + FieldDeclaration fieldDecl = (FieldDeclaration) field.get(); return filterField(fieldDecl); } @@ -81,55 +93,75 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { - for (EclipseNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, source, whineIfExists); - } - - private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { - if (fieldNode.getKind() != Kind.FIELD) { - errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field"); + FieldNameConstants annotationInstance = annotation.getInstance(); + AccessLevel level = annotationInstance.level(); + boolean asEnum = annotationInstance.asEnum(); + boolean usingLombokv1_18_2 = annotation.isExplicit("prefix") || annotation.isExplicit("suffix") || node.getKind() == Kind.FIELD; + + if (usingLombokv1_18_2) { + annotationNode.addError("@FieldNameConstants has been redesigned in lombok v1.18.4; please upgrade your project dependency on lombok. See https://projectlombok.org/features/experimental/FieldNameConstants for more information."); return; } - FieldDeclaration field = (FieldDeclaration) fieldNode.get(); - String fieldName = new String(field.name); - String constantName = prefix + HandlerUtil.camelCaseToConstant(fieldName) + suffix; - if (constantName.equals(fieldName)) { - fieldNode.addWarning("Not generating constant for this field: The name of the constant would be equal to the name of this field."); + if (level == AccessLevel.NONE) { + annotationNode.addWarning("AccessLevel.NONE is not compatible with @FieldNameConstants. If you don't want the inner type, simply remove FieldNameConstants."); return; } - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long) pS << 32 | pE; - FieldDeclaration fieldConstant = new FieldDeclaration(constantName.toCharArray(), pS,pE); - fieldConstant.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - fieldConstant.modifiers = toEclipseModifier(level) | Modifier.STATIC | Modifier.FINAL; - fieldConstant.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p,p,p}); - fieldConstant.initialization = new StringLiteral(field.name, pS, pE, 0); - injectField(fieldNode.up(), fieldConstant); + String innerTypeName = annotationInstance.innerTypeName(); + if (innerTypeName.isEmpty()) innerTypeName = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_INNER_TYPE_NAME); + if (innerTypeName == null || innerTypeName.isEmpty()) innerTypeName = "Fields"; + + generateFieldNameConstantsForType(node, annotationNode, level, asEnum, innerTypeName, annotationInstance.onlyExplicitlyIncluded()); + } + + private void createInnerTypeFieldNameConstants(EclipseNode typeNode, ASTNode source, AccessLevel level, List fields, boolean asEnum, String innerTypeName) { + if (fields.isEmpty()) return; + + TypeDeclaration parent = (TypeDeclaration) typeNode.get(); + TypeDeclaration innerType = new TypeDeclaration(parent.compilationResult); + innerType.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + innerType.modifiers = toEclipseModifier(level) | (asEnum ? ClassFileConstants.AccEnum : ClassFileConstants.AccStatic | ClassFileConstants.AccFinal); + char[] name = innerTypeName.toCharArray(); + innerType.name = name; + innerType.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + EclipseNode innerNode = injectType(typeNode, innerType); + + ConstructorDeclaration constructor = new ConstructorDeclaration(parent.compilationResult); + constructor.selector = name; + constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; + constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; + constructor.modifiers = ClassFileConstants.AccPrivate; + ExplicitConstructorCall superCall = new ExplicitConstructorCall(0); + superCall.sourceStart = source.sourceStart; + superCall.sourceEnd = source.sourceEnd; + superCall.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + constructor.constructorCall = superCall; + if (!asEnum) constructor.statements = new Statement[0]; + + injectMethod(innerNode, constructor); + + if (asEnum) injectMethod(innerNode, new Clinit(parent.compilationResult)); + + for (EclipseNode fieldNode : fields) { + FieldDeclaration field = (FieldDeclaration) fieldNode.get(); + char[] fName = field.name; + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long) pS << 32 | pE; + FieldDeclaration fieldConstant = new FieldDeclaration(fName, pS, pE); + fieldConstant.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + fieldConstant.modifiers = asEnum ? 0 : ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; + fieldConstant.type = asEnum ? null : new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p, p, p}); + if (asEnum) { + AllocationExpression ac = new AllocationExpression(); + ac.enumConstant = fieldConstant; + ac.sourceStart = source.sourceStart; + ac.sourceEnd = source.sourceEnd; + fieldConstant.initialization = ac; + } else { + fieldConstant.initialization = new StringLiteral(field.name, pS, pE, 0); + } + injectField(innerNode, fieldConstant); + } } } diff --git a/src/core/lombok/experimental/FieldNameConstants.java b/src/core/lombok/experimental/FieldNameConstants.java index 31c2970c..d6886890 100644 --- a/src/core/lombok/experimental/FieldNameConstants.java +++ b/src/core/lombok/experimental/FieldNameConstants.java @@ -29,12 +29,32 @@ import java.lang.annotation.Target; import lombok.AccessLevel; /** - * Generates String constants containing the field name for each field. + * Generates an inner type, containing String constants containing the field name for each field. Alternatively, generates an inner enum with enum values matching each field name. */ -@Target({ElementType.TYPE, ElementType.FIELD}) +@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface FieldNameConstants { lombok.AccessLevel level() default AccessLevel.PUBLIC; - String prefix() default " CONFIG DEFAULT "; - String suffix() default " CONFIG DEFAULT "; + boolean asEnum() default false; + String innerTypeName() default ""; + + /** + * Only include fields and methods explicitly marked with {@code @FieldNameConstants.Include}. + * Normally, all (non-static) fields are included by default. + */ + boolean onlyExplicitlyIncluded() default false; + + /** + * If present, do not include this field in the generated fieldnames inner type. + */ + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.SOURCE) + public @interface Exclude {} + + /** + * If present, include this field in the generated fieldnames inner type (default). + */ + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.SOURCE) + public @interface Include {} } diff --git a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java index 8ff136fc..5b120948 100644 --- a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java @@ -24,13 +24,11 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage; import static lombok.javac.handlers.JavacHandlerUtil.*; -import java.lang.reflect.Modifier; -import java.util.Collection; +import java.util.ArrayList; import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; -import lombok.core.handlers.HandlerUtil; import lombok.core.AnnotationValues; import lombok.experimental.FieldNameConstants; import lombok.javac.JavacAnnotationHandler; @@ -40,16 +38,23 @@ import lombok.javac.JavacTreeMaker; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; +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.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; @ProviderFor(JavacAnnotationHandler.class) public class HandleFieldNameConstants extends JavacAnnotationHandler { - public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, String prefix, String suffix) { + public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean asEnum, String innerTypeName, boolean onlyExplicit) { JCClassDecl typeDecl = null; if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get(); @@ -57,22 +62,31 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler qualified = new ArrayList(); + for (JavacNode field : typeNode.down()) { - if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix); + if (fieldQualifiesForFieldNameConstantsGeneration(field, onlyExplicit)) qualified.add(field); + } + + if (qualified.isEmpty()) { + errorNode.addWarning("No fields qualify for @FieldNameConstants, therefore this annotation does nothing"); + } else { + createInnerTypeFieldNameConstants(typeNode, errorNode.get(), level, qualified, asEnum, innerTypeName); } } - private void generateFieldNameConstantsForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, String prefix, String suffix) { - if (hasAnnotation(FieldNameConstants.class, fieldNode)) return; - createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, false); - } - - private boolean fieldQualifiesForFieldNameConstantsGeneration(JavacNode field) { + private boolean fieldQualifiesForFieldNameConstantsGeneration(JavacNode field, boolean onlyExplicit) { if (field.getKind() != Kind.FIELD) return false; + boolean exclAnn = JavacHandlerUtil.hasAnnotationAndDeleteIfNeccessary(FieldNameConstants.Exclude.class, field); + boolean inclAnn = JavacHandlerUtil.hasAnnotationAndDeleteIfNeccessary(FieldNameConstants.Include.class, field); + if (exclAnn) return false; + if (inclAnn) return true; + if (onlyExplicit) return false; + JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); if (fieldDecl.name.toString().startsWith("$")) return false; if ((fieldDecl.mods.flags & Flags.STATIC) != 0) return false; @@ -82,56 +96,61 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler annotation, JCAnnotation ast, JavacNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants"); - Collection fields = annotationNode.upFromAnnotationToFields(); deleteAnnotationIfNeccessary(annotationNode, FieldNameConstants.class); deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode node = annotationNode.up(); - FieldNameConstants annotatationInstance = annotation.getInstance(); - AccessLevel level = annotatationInstance.level(); - String prefix = annotatationInstance.prefix(); - String suffix = annotatationInstance.suffix(); - if (prefix.equals(" CONFIG DEFAULT ")) prefix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_PREFIX); - if (suffix.equals(" CONFIG DEFAULT ")) suffix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_SUFFIX); - if (prefix == null) prefix = "FIELD_"; - if (suffix == null) suffix = ""; - if (node == null) return; - switch (node.getKind()) { - case FIELD: - if (level != AccessLevel.NONE) createFieldNameConstantsForFields(level, prefix, suffix, fields, annotationNode, annotationNode, true); - break; - case TYPE: - if (level == AccessLevel.NONE) { - annotationNode.addWarning("type-level '@FieldNameConstants' does not work with AccessLevel.NONE."); - return; - } - generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix); - break; - } - } - - private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection fieldNode