From 0375f1a9e8f606588d4e136fc718a6876ff0ae4f Mon Sep 17 00:00:00 2001 From: Thomas Klambauer Date: Tue, 17 Jul 2018 13:35:34 +0200 Subject: [PATCH 01/40] 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 = ""
 }

From a195a47337f592eb117f519f7a1a42f0d8f570d1 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 17 Jul 2018 22:32:24 +0200 Subject: [PATCH 02/40] 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; From ff739d6d5a6a68f8d87480be7b0c0104e08f77e0 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 19 Jul 2018 21:46:39 +0200 Subject: [PATCH 03/40] 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 From be1cfd2f59933725726ec5810e0c189a4aca6ad7 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Sun, 8 Jul 2018 16:52:14 +0200 Subject: [PATCH 04/40] 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); } /** From 111d0a5f16667824d0a73b733624e6deffe19a0e Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 21:10:20 +0200 Subject: [PATCH 05/40] =?UTF-8?q?Fixes=20issue=20#1789=20-=20picking=20ano?= =?UTF-8?q?ther=20workspace=20duplicates=20the=20=E2=80=98lombok=20is=20in?= =?UTF-8?q?stalled=E2=80=99=20text=20in=20the=20eclipse=20about=20dialog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../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; From 5ec61bb62d3dd2d9509ade090e750dd43e36c0f3 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 21:41:17 +0200 Subject: [PATCH 06/40] =?UTF-8?q?[fixes=20issue=20#1759]=20We=20removed=20?= =?UTF-8?q?the=20=E2=80=98flag=20usage=E2=80=99=20check=20on=20builder=20i?= =?UTF-8?q?nstead=20of=20replacing=20it=20with=20the=20non-experimental=20?= =?UTF-8?q?check=20about=203=20years=20ago=20when=20builder=20moved=20out?= =?UTF-8?q?=20of=20experimental.=20The=20check=20has=20now=20been=20restor?= =?UTF-8?q?ed.?= 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. From 7c3724c9dc03684b9e4ecb9b33296c894138add6 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 22:04:52 +0200 Subject: [PATCH 07/40] =?UTF-8?q?[Fixes=20issue=20#1783]=20lombok.var=20/?= =?UTF-8?q?=20lombok.experimental.var=20import=20would=20be=20removed=20by?= =?UTF-8?q?=20eclipse=E2=80=99s=20organize=20imports.?= 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); } From 7e94041dbc177476020969b00d3411020418f903 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 25 Jul 2018 23:19:00 +0200 Subject: [PATCH 08/40] =?UTF-8?q?Added=20key=20=E2=80=98dangerousconfig.lo?= =?UTF-8?q?mbok.disable=E2=80=99.?= 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 ++++++++++----- .../core/configuration/ConfigurationApp.java | 7 ++++--- .../core/configuration/ConfigurationKey.java | 12 +++++++++++- .../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(); } }); From dc715da8b79bff32116ac477d0ac04875bd21167 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 26 Jul 2018 00:00:24 +0200 Subject: [PATCH 09/40] 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 From 61fbd4a7f82180871e635a0ca80248e0cec02cf3 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 26 Jul 2018 00:17:09 +0200 Subject: [PATCH 10/40] 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 From 3d432c38d0cfeb36b8e7402eca56faaafcf7bac7 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 29 Jul 2018 16:37:21 +0200 Subject: [PATCH 11/40] code impl of FieldNameConstants rewrite + test updates for it --- src/core/lombok/ConfigurationKeys.java | 11 +- .../handlers/HandleFieldNameConstants.java | 150 +++++++++++------- .../experimental/FieldNameConstants.java | 28 +++- .../handlers/HandleFieldNameConstants.java | 137 +++++++++------- .../FieldNameConstantsBasic.java | 8 +- .../FieldNameConstantsConfigKeys.java | 7 +- .../FieldNameConstantsEnum.java | 10 ++ .../FieldNameConstantsWeird.java | 6 - .../after-ecj/FieldNameConstantsBasic.java | 18 ++- .../FieldNameConstantsConfigKeys.java | 13 +- .../after-ecj/FieldNameConstantsEnum.java | 23 +++ .../after-ecj/FieldNameConstantsWeird.java | 13 -- .../before/FieldNameConstantsBasic.java | 4 +- .../before/FieldNameConstantsConfigKeys.java | 3 +- .../before/FieldNameConstantsEnum.java | 13 ++ .../before/FieldNameConstantsWeird.java | 12 -- .../FieldNameConstantsWeird.java.messages | 1 - .../FieldNameConstantsWeird.java.messages | 1 - 18 files changed, 277 insertions(+), 181 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 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); } - generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix); - break; + injectField(innerNode, fieldConstant); } } - - private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection 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"); - 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."); - 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); - } } 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; + 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; + } + + + 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; + } + + 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(JavacNode typeNode, DiagnosticPosition pos, AccessLevel level, java.util.List fields, boolean asEnum, String innerTypeName) { + if (fields.isEmpty()) return; + + JavacTreeMaker maker = typeNode.getTreeMaker(); + JCModifiers mods = maker.Modifiers(toJavacModifier(level) | (asEnum ? Flags.ENUM : Flags.STATIC | Flags.FINAL)); + + Name fieldsName = typeNode.toName(innerTypeName); + JCClassDecl innerType = maker.ClassDef(mods, fieldsName, List.nil(), null, List.nil(), List.nil()); + JavacNode innerNode = injectType(typeNode, innerType); + + JCModifiers genConstrMods = maker.Modifiers(Flags.GENERATEDCONSTR | (asEnum ? 0L : Flags.PRIVATE)); + JCBlock genConstrBody = maker.Block(0L, List.of(maker.Exec(maker.Apply(List.nil(), maker.Ident(typeNode.toName("super")), List.nil())))); + JCMethodDecl genConstr = maker.MethodDef(genConstrMods, typeNode.toName(""), null, List.nil(), List.nil(), List.nil(), genConstrBody, null); + + injectMethod(innerNode, genConstr); + + for (JavacNode field : fields) { + JCModifiers enumValueMods = maker.Modifiers(Flags.PUBLIC | Flags.STATIC | Flags.FINAL | (asEnum ? Flags.ENUM : 0L)); + JCExpression returnType; + JCExpression init; + if (asEnum) { + returnType = maker.Ident(fieldsName); + init = maker.NewClass(null, List.nil(), maker.Ident(fieldsName), List.nil(), null); + } else { + returnType = chainDots(field, "java", "lang", "String"); + init = maker.Literal(field.getName()); } - generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix); - break; + JCVariableDecl enumField = maker.VarDef(enumValueMods, ((JCVariableDecl) field.get()).name, returnType, init); + injectField(innerNode, enumField); } } - - private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection fieldNodes, JavacNode annotationNode, JavacNode errorNode, boolean whineIfExists) { - for (JavacNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, whineIfExists); - } - - private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, JavacNode fieldNode, JavacNode source, boolean whineIfExists) { - if (fieldNode.getKind() != Kind.FIELD) { - source.addError("@FieldNameConstants is only supported on a class, an enum, or a field"); - return; - } - - JCVariableDecl field = (JCVariableDecl) fieldNode.get(); - String fieldName = field.name.toString(); - 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."); - return; - } - - JavacTreeMaker treeMaker = fieldNode.getTreeMaker(); - JCModifiers modifiers = treeMaker.Modifiers(toJavacModifier(level) | Modifier.STATIC | Modifier.FINAL); - JCExpression returnType = chainDots(fieldNode, "java", "lang", "String"); - JCExpression init = treeMaker.Literal(fieldNode.getName()); - JCVariableDecl fieldConstant = treeMaker.VarDef(modifiers, fieldNode.toName(constantName), returnType, init); - injectField(fieldNode.up(), fieldConstant); - } -} \ No newline at end of file +} diff --git a/test/transform/resource/after-delombok/FieldNameConstantsBasic.java b/test/transform/resource/after-delombok/FieldNameConstantsBasic.java index 4e547aa5..8be45d2b 100644 --- a/test/transform/resource/after-delombok/FieldNameConstantsBasic.java +++ b/test/transform/resource/after-delombok/FieldNameConstantsBasic.java @@ -1,8 +1,12 @@ public class FieldNameConstantsBasic { - protected static final java.lang.String FIELD_I_AM_A_DVD_PLAYER = "iAmADvdPlayer"; - public static final java.lang.String FIELD_BUT_PRINT_ME_PLEASE = "butPrintMePlease"; String iAmADvdPlayer; int $skipMe; static double skipMeToo; + int andMe; String butPrintMePlease; + @java.lang.SuppressWarnings("all") + static final class Fields { + public static final java.lang.String butPrintMePlease = "butPrintMePlease"; + public static final java.lang.String iAmADvdPlayer = "iAmADvdPlayer"; + } } diff --git a/test/transform/resource/after-delombok/FieldNameConstantsConfigKeys.java b/test/transform/resource/after-delombok/FieldNameConstantsConfigKeys.java index c71b9264..4c2a53e3 100644 --- a/test/transform/resource/after-delombok/FieldNameConstantsConfigKeys.java +++ b/test/transform/resource/after-delombok/FieldNameConstantsConfigKeys.java @@ -1,4 +1,7 @@ public class FieldNameConstantsConfigKeys { - public static final java.lang.String I_AM_A_DVD_PLAYER_SFX = "iAmADvdPlayer"; String iAmADvdPlayer; -} + @java.lang.SuppressWarnings("all") + public static final class Foobar { + public static final java.lang.String iAmADvdPlayer = "iAmADvdPlayer"; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/FieldNameConstantsEnum.java b/test/transform/resource/after-delombok/FieldNameConstantsEnum.java new file mode 100644 index 00000000..c3fbf0c2 --- /dev/null +++ b/test/transform/resource/after-delombok/FieldNameConstantsEnum.java @@ -0,0 +1,10 @@ +public class FieldNameConstantsEnum { + String iAmADvdPlayer; + int $dontSkipMe; + static double alsoDontSkipMe; + int butSkipMe; + @java.lang.SuppressWarnings("all") + public enum TypeTest { + iAmADvdPlayer, $dontSkipMe, alsoDontSkipMe; + } +} diff --git a/test/transform/resource/after-delombok/FieldNameConstantsWeird.java b/test/transform/resource/after-delombok/FieldNameConstantsWeird.java deleted file mode 100644 index 6940f628..00000000 --- a/test/transform/resource/after-delombok/FieldNameConstantsWeird.java +++ /dev/null @@ -1,6 +0,0 @@ -public class FieldNameConstantsWeird { - public static final java.lang.String FIELD_AZ = "A"; - String iAmADvdPlayer; - String X; - String A; -} diff --git a/test/transform/resource/after-ecj/FieldNameConstantsBasic.java b/test/transform/resource/after-ecj/FieldNameConstantsBasic.java index f77203ba..674dd602 100644 --- a/test/transform/resource/after-ecj/FieldNameConstantsBasic.java +++ b/test/transform/resource/after-ecj/FieldNameConstantsBasic.java @@ -1,15 +1,23 @@ import lombok.experimental.FieldNameConstants; import lombok.AccessLevel; -public @FieldNameConstants class FieldNameConstantsBasic { - public static final java.lang.String FIELD_BUT_PRINT_ME_PLEASE = "butPrintMePlease"; - protected static final java.lang.String FIELD_I_AM_A_DVD_PLAYER = "iAmADvdPlayer"; - @FieldNameConstants(level = AccessLevel.PROTECTED) String iAmADvdPlayer; +public @FieldNameConstants(level = AccessLevel.PACKAGE) class FieldNameConstantsBasic { + static final @java.lang.SuppressWarnings("all") class Fields { + public static final java.lang.String butPrintMePlease = "butPrintMePlease"; + public static final java.lang.String iAmADvdPlayer = "iAmADvdPlayer"; + () { + } + private @java.lang.SuppressWarnings("all") Fields() { + super(); + } + } + String iAmADvdPlayer; int $skipMe; static double skipMeToo; + @FieldNameConstants.Exclude int andMe; String butPrintMePlease; () { } public FieldNameConstantsBasic() { super(); } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/FieldNameConstantsConfigKeys.java b/test/transform/resource/after-ecj/FieldNameConstantsConfigKeys.java index 44629ee5..7eb97364 100644 --- a/test/transform/resource/after-ecj/FieldNameConstantsConfigKeys.java +++ b/test/transform/resource/after-ecj/FieldNameConstantsConfigKeys.java @@ -1,9 +1,14 @@ public @lombok.experimental.FieldNameConstants class FieldNameConstantsConfigKeys { - public static final java.lang.String I_AM_A_DVD_PLAYER_SFX = "iAmADvdPlayer"; - String iAmADvdPlayer; - () { + public static final @java.lang.SuppressWarnings("all") class Foobar { + public static final java.lang.String iAmADvdPlayer = "iAmADvdPlayer"; + () { + } + private @java.lang.SuppressWarnings("all") Foobar() { + super(); + } } + String iAmADvdPlayer; public FieldNameConstantsConfigKeys() { super(); } -} +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/FieldNameConstantsEnum.java b/test/transform/resource/after-ecj/FieldNameConstantsEnum.java new file mode 100644 index 00000000..053a6e7a --- /dev/null +++ b/test/transform/resource/after-ecj/FieldNameConstantsEnum.java @@ -0,0 +1,23 @@ +import lombok.experimental.FieldNameConstants; +import lombok.AccessLevel; +public @FieldNameConstants(onlyExplicitlyIncluded = true,asEnum = true,innerTypeName = "TypeTest") class FieldNameConstantsEnum { + public @java.lang.SuppressWarnings("all") enum TypeTest { + iAmADvdPlayer(), + $dontSkipMe(), + alsoDontSkipMe(), + private @java.lang.SuppressWarnings("all") TypeTest() { + super(); + } + () { + } + } + @FieldNameConstants.Include String iAmADvdPlayer; + @FieldNameConstants.Include int $dontSkipMe; + static @FieldNameConstants.Include double alsoDontSkipMe; + int butSkipMe; + () { + } + public FieldNameConstantsEnum() { + super(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/FieldNameConstantsWeird.java b/test/transform/resource/after-ecj/FieldNameConstantsWeird.java deleted file mode 100644 index 9958f664..00000000 --- a/test/transform/resource/after-ecj/FieldNameConstantsWeird.java +++ /dev/null @@ -1,13 +0,0 @@ -import lombok.experimental.FieldNameConstants; -import lombok.AccessLevel; -public @FieldNameConstants class FieldNameConstantsWeird { - public static final java.lang.String FIELD_AZ = "A"; - @FieldNameConstants(level = AccessLevel.NONE) String iAmADvdPlayer; - @FieldNameConstants(prefix = "") String X; - @FieldNameConstants(suffix = "Z") String A; - () { - } - public FieldNameConstantsWeird() { - super(); - } -} diff --git a/test/transform/resource/before/FieldNameConstantsBasic.java b/test/transform/resource/before/FieldNameConstantsBasic.java index 1bc15d84..2842dea3 100644 --- a/test/transform/resource/before/FieldNameConstantsBasic.java +++ b/test/transform/resource/before/FieldNameConstantsBasic.java @@ -1,11 +1,11 @@ import lombok.experimental.FieldNameConstants; import lombok.AccessLevel; -@FieldNameConstants +@FieldNameConstants(level = AccessLevel.PACKAGE) public class FieldNameConstantsBasic { - @FieldNameConstants(level = AccessLevel.PROTECTED) String iAmADvdPlayer; int $skipMe; static double skipMeToo; + @FieldNameConstants.Exclude int andMe; String butPrintMePlease; } diff --git a/test/transform/resource/before/FieldNameConstantsConfigKeys.java b/test/transform/resource/before/FieldNameConstantsConfigKeys.java index ab8e3091..5595222c 100644 --- a/test/transform/resource/before/FieldNameConstantsConfigKeys.java +++ b/test/transform/resource/before/FieldNameConstantsConfigKeys.java @@ -1,5 +1,4 @@ -//CONF: lombok.fieldNameConstants.prefix = -//CONF: lombok.fieldNameConstants.suffix = _SFX +//CONF: lombok.fieldNameConstants.innerTypeName = Foobar @lombok.experimental.FieldNameConstants public class FieldNameConstantsConfigKeys { diff --git a/test/transform/resource/before/FieldNameConstantsEnum.java b/test/transform/resource/before/FieldNameConstantsEnum.java new file mode 100644 index 00000000..d56bb280 --- /dev/null +++ b/test/transform/resource/before/FieldNameConstantsEnum.java @@ -0,0 +1,13 @@ +import lombok.experimental.FieldNameConstants; +import lombok.AccessLevel; + +@FieldNameConstants(onlyExplicitlyIncluded = true, asEnum = true, innerTypeName = "TypeTest") +public class FieldNameConstantsEnum { + @FieldNameConstants.Include + String iAmADvdPlayer; + @FieldNameConstants.Include + int $dontSkipMe; + @FieldNameConstants.Include + static double alsoDontSkipMe; + int butSkipMe; +} diff --git a/test/transform/resource/before/FieldNameConstantsWeird.java b/test/transform/resource/before/FieldNameConstantsWeird.java deleted file mode 100644 index 74ec299a..00000000 --- a/test/transform/resource/before/FieldNameConstantsWeird.java +++ /dev/null @@ -1,12 +0,0 @@ -import lombok.experimental.FieldNameConstants; -import lombok.AccessLevel; - -@FieldNameConstants -public class FieldNameConstantsWeird { - @FieldNameConstants(level = AccessLevel.NONE) - String iAmADvdPlayer; - @FieldNameConstants(prefix = "") - String X; - @FieldNameConstants(suffix = "Z") - String A; -} diff --git a/test/transform/resource/messages-delombok/FieldNameConstantsWeird.java.messages b/test/transform/resource/messages-delombok/FieldNameConstantsWeird.java.messages deleted file mode 100644 index 02a38d58..00000000 --- a/test/transform/resource/messages-delombok/FieldNameConstantsWeird.java.messages +++ /dev/null @@ -1 +0,0 @@ -9 Not generating constant for this field: The name of the constant would be equal to the name of this field. diff --git a/test/transform/resource/messages-ecj/FieldNameConstantsWeird.java.messages b/test/transform/resource/messages-ecj/FieldNameConstantsWeird.java.messages deleted file mode 100644 index 02a38d58..00000000 --- a/test/transform/resource/messages-ecj/FieldNameConstantsWeird.java.messages +++ /dev/null @@ -1 +0,0 @@ -9 Not generating constant for this field: The name of the constant would be equal to the name of this field. From eeab3c0021503bca69012cf71cbbfe2505be2293 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 29 Jul 2018 16:37:54 +0200 Subject: [PATCH 12/40] A few upgrades for the printers used with @lombok.core.PrintAST. --- .../lombok/eclipse/EclipseASTVisitor.java | 105 ++++++++++++++++-- src/core/lombok/javac/JavacASTVisitor.java | 14 ++- 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/src/core/lombok/eclipse/EclipseASTVisitor.java b/src/core/lombok/eclipse/EclipseASTVisitor.java index f5b49cbb..63557f41 100644 --- a/src/core/lombok/eclipse/EclipseASTVisitor.java +++ b/src/core/lombok/eclipse/EclipseASTVisitor.java @@ -26,7 +26,9 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.io.PrintStream; import java.lang.reflect.Modifier; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.Block; @@ -38,6 +40,7 @@ import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; /** * Implement so you can ask any EclipseAST.Node to traverse depth-first through all children, @@ -199,8 +202,82 @@ public interface EclipseASTVisitor { print(""); } + private String printFlags(int flags, ASTNode node) { + StringBuilder out = new StringBuilder(); + if ((flags & ClassFileConstants.AccPublic) != 0) { + flags &= ~ClassFileConstants.AccPublic; + out.append("public "); + } + if ((flags & ClassFileConstants.AccPrivate) != 0) { + flags &= ~ClassFileConstants.AccPrivate; + out.append("private "); + } + if ((flags & ClassFileConstants.AccProtected) != 0) { + flags &= ~ClassFileConstants.AccProtected; + out.append("protected "); + } + if ((flags & ClassFileConstants.AccStatic) != 0) { + flags &= ~ClassFileConstants.AccStatic; + out.append("static "); + } + if ((flags & ClassFileConstants.AccFinal) != 0) { + flags &= ~ClassFileConstants.AccFinal; + out.append("final "); + } + if ((flags & ClassFileConstants.AccSynchronized) != 0) { + flags &= ~ClassFileConstants.AccSynchronized; + out.append("synchronized "); + } + if ((flags & ClassFileConstants.AccNative) != 0) { + flags &= ~ClassFileConstants.AccNative; + out.append("native "); + } + if ((flags & ClassFileConstants.AccInterface) != 0) { + flags &= ~ClassFileConstants.AccInterface; + out.append("interface "); + } + if ((flags & ClassFileConstants.AccAbstract) != 0) { + flags &= ~ClassFileConstants.AccAbstract; + out.append("abstract "); + } + if ((flags & ClassFileConstants.AccStrictfp) != 0) { + flags &= ~ClassFileConstants.AccStrictfp; + out.append("strictfp "); + } + if ((flags & ClassFileConstants.AccSynthetic) != 0) { + flags &= ~ClassFileConstants.AccSynthetic; + out.append("synthetic "); + } + if ((flags & ClassFileConstants.AccAnnotation) != 0) { + flags &= ~ClassFileConstants.AccAnnotation; + out.append("annotation "); + } + if ((flags & ClassFileConstants.AccEnum) != 0) { + flags &= ~ClassFileConstants.AccEnum; + out.append("enum "); + } + + if ((flags & ClassFileConstants.AccVolatile) != 0) { + flags &= ~ClassFileConstants.AccVolatile; + if (node instanceof FieldDeclaration) out.append("volatile "); + else out.append("volatile/bridge "); + } + if ((flags & ClassFileConstants.AccTransient) != 0) { + flags &= ~ClassFileConstants.AccTransient; + if (node instanceof Argument) out.append("varargs "); + else if (node instanceof FieldDeclaration) out.append("transient "); + else out.append("transient/varargs "); + } + + if (flags != 0) { + out.append(String.format(" 0x%08X ", flags)); + } + + return out.toString().trim(); + } + public void visitType(EclipseNode node, TypeDeclaration type) { - print("", str(type.name), isGenerated(type) ? " (GENERATED)" : "", position(node)); + print(" %s", str(type.name), isGenerated(type) ? " (GENERATED)" : "", position(node), printFlags(type.modifiers, type)); indent++; if (printContent) { print("%s", type); @@ -239,8 +316,8 @@ public interface EclipseASTVisitor { } public void visitField(EclipseNode node, FieldDeclaration field) { - print("", isGenerated(field) ? " (GENERATED)" : "", - str(field.type), str(field.name), field.initialization, position(node)); + print(" %s", isGenerated(field) ? " (GENERATED)" : "", + str(field.type), str(field.name), field.initialization, position(node), printFlags(field.modifiers, field)); indent++; if (printContent) { if (field.initialization != null) print("%s", field.initialization); @@ -260,9 +337,13 @@ public interface EclipseASTVisitor { public void visitMethod(EclipseNode node, AbstractMethodDeclaration method) { String type = method instanceof ConstructorDeclaration ? "CONSTRUCTOR" : "METHOD"; - print("<%s %s: %s%s%s>", type, str(method.selector), method.statements != null ? "filled" : "blank", - isGenerated(method) ? " (GENERATED)" : "", position(node)); + print("<%s %s: %s%s%s> %s", type, str(method.selector), method.statements != null ? ("filled(" + method.statements.length + ")") : "blank", + isGenerated(method) ? " (GENERATED)" : "", position(node), printFlags(method.modifiers, method)); indent++; + if (method instanceof ConstructorDeclaration) { + ConstructorDeclaration cd = (ConstructorDeclaration) method; + print("--> constructorCall: %s", cd.constructorCall == null ? "-NONE-" : cd.constructorCall); + } if (printContent) { if (method.statements != null) print("%s", method); disablePrinting++; @@ -281,7 +362,8 @@ public interface EclipseASTVisitor { } public void visitMethodArgument(EclipseNode node, Argument arg, AbstractMethodDeclaration method) { - print("", isGenerated(arg) ? " (GENERATED)" : "", str(arg.type), str(arg.name), arg.initialization, position(node)); + print(" %s", isGenerated(arg) ? " (GENERATED)" : "", + str(arg.type), str(arg.name), arg.initialization, position(node), printFlags(arg.modifiers, arg)); indent++; } @@ -295,7 +377,8 @@ public interface EclipseASTVisitor { } public void visitLocal(EclipseNode node, LocalDeclaration local) { - print("", isGenerated(local) ? " (GENERATED)" : "", str(local.type), str(local.name), local.initialization, position(node)); + print(" %s", isGenerated(local) ? " (GENERATED)" : "", + str(local.type), str(local.name), local.initialization, position(node), printFlags(local.modifiers, local)); indent++; } @@ -310,6 +393,14 @@ public interface EclipseASTVisitor { public void visitStatement(EclipseNode node, Statement statement) { print("<%s%s%s>", statement.getClass(), isGenerated(statement) ? " (GENERATED)" : "", position(node)); + if (statement instanceof AllocationExpression) { + AllocationExpression alloc = (AllocationExpression) statement; + print(" --> arguments: %s", alloc.arguments == null ? "NULL" : alloc.arguments.length); + print(" --> genericTypeArguments: %s", alloc.genericTypeArguments == null ? "NULL" : alloc.genericTypeArguments.length); + print(" --> typeArguments: %s", alloc.typeArguments == null ? "NULL" : alloc.typeArguments.length); + print(" --> enumConstant: %s", alloc.enumConstant); + print(" --> inferredReturnType: %s", alloc.inferredReturnType); + } indent++; print("%s", statement); } diff --git a/src/core/lombok/javac/JavacASTVisitor.java b/src/core/lombok/javac/JavacASTVisitor.java index 565980f9..d4f8f731 100644 --- a/src/core/lombok/javac/JavacASTVisitor.java +++ b/src/core/lombok/javac/JavacASTVisitor.java @@ -149,8 +149,12 @@ public interface JavacASTVisitor { print(""); } + private String printFlags(long f) { + return Flags.toString(f); + } + @Override public void visitType(JavacNode node, JCClassDecl type) { - print("", type.name); + print(" %s", type.name, printFlags(type.mods.flags)); indent++; if (printContent) { print("%s", type); @@ -185,7 +189,7 @@ public interface JavacASTVisitor { } @Override public void visitField(JavacNode node, JCVariableDecl field) { - print("", field.vartype, field.name); + print(" %s", field.vartype, field.name, printFlags(field.mods.flags)); indent++; if (printContent) { if (field.init != null) print("%s", field.init); @@ -210,7 +214,7 @@ public interface JavacASTVisitor { type = "DEFAULTCONSTRUCTOR"; } else type = "CONSTRUCTOR"; } else type = "METHOD"; - print("<%s %s> returns: %s", type, method.name, method.restype); + print("<%s %s> %s returns: %s", type, method.name, printFlags(method.mods.flags), method.restype); indent++; if (printContent) { if (method.body == null) print("(ABSTRACT)"); @@ -230,7 +234,7 @@ public interface JavacASTVisitor { } @Override public void visitMethodArgument(JavacNode node, JCVariableDecl arg, JCMethodDecl method) { - print("", arg.vartype, arg.name); + print(" %s", arg.vartype, arg.name, printFlags(arg.mods.flags)); indent++; } @@ -244,7 +248,7 @@ public interface JavacASTVisitor { } @Override public void visitLocal(JavacNode node, JCVariableDecl local) { - print("", local.vartype, local.name); + print(" %s", local.vartype, local.name, printFlags(local.mods.flags)); indent++; } From b9fb35cb8e81d73b9b9b650022a1564b14761885 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 29 Jul 2018 16:38:16 +0200 Subject: [PATCH 13/40] Printing missing gradle integration would print for any non-javac, non-gradle compiler. Fixed that. --- src/core/lombok/core/AnnotationProcessor.java | 25 ++++++++++--------- .../javac/handlers/HandleFieldDefaults.java | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index 04448ecb..89dfa555 100644 --- a/src/core/lombok/core/AnnotationProcessor.java +++ b/src/core/lombok/core/AnnotationProcessor.java @@ -49,7 +49,7 @@ import lombok.patcher.ClassRootFinder; @SupportedAnnotationTypes("*") public class AnnotationProcessor extends AbstractProcessor { - + private static String trace(Throwable t) { StringWriter w = new StringWriter(); t.printStackTrace(new PrintWriter(w, true)); @@ -65,7 +65,7 @@ public class AnnotationProcessor extends AbstractProcessor { private final List registered = Arrays.asList(new JavacDescriptor(), new EcjDescriptor()); private final List active = new ArrayList(); private final List delayedWarnings = new ArrayList(); - + /** * This method is a simplified version of {@link lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment} * It simply returns the processing environment, but in case of gradle incremental compilation, @@ -73,34 +73,35 @@ public class AnnotationProcessor extends AbstractProcessor { */ public static ProcessingEnvironment getJavacProcessingEnvironment(ProcessingEnvironment procEnv, List delayedWarnings) { ProcessingEnvironment javacProcEnv = tryRecursivelyObtainJavacProcessingEnvironment(procEnv); - + if (javacProcEnv == null) { - delayedWarnings.add("Can't get the delegate of the gradle IncrementalProcessingEnvironment."); + if (!procEnv.getClass().getName().startsWith("org.eclipse.jdt.")) { + delayedWarnings.add("Can't get the delegate of the gradle IncrementalProcessingEnvironment."); + } } - + return javacProcEnv; } - + private static ProcessingEnvironment tryRecursivelyObtainJavacProcessingEnvironment(ProcessingEnvironment procEnv) { if (procEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) { return procEnv; } - + for (Class procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { try { Field field = procEnvClass.getDeclaredField("delegate"); field.setAccessible(true); Object delegate = field.get(procEnv); - + return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate); } catch (final Exception e) { // no valid delegate, try superclass } } - + return null; } - static class JavacDescriptor extends ProcessorDescriptor { private Processor processor; @@ -111,9 +112,9 @@ public class AnnotationProcessor extends AbstractProcessor { @Override boolean want(ProcessingEnvironment procEnv, List delayedWarnings) { ProcessingEnvironment javacProcEnv = getJavacProcessingEnvironment(procEnv, delayedWarnings); - + if (javacProcEnv == null) return false; - + try { ClassLoader classLoader = findAndPatchClassLoader(javacProcEnv); processor = (Processor) Class.forName("lombok.javac.apt.LombokProcessor", false, classLoader).newInstance(); diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index 52f6c39c..aa381c0d 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -44,7 +44,7 @@ import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; /** - * Handles the {@code lombok.FieldDefaults} annotation for eclipse. + * Handles the {@code lombok.FieldDefaults} annotation for javac. */ @ProviderFor(JavacASTVisitor.class) @HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier. From e964f5eec6015564d561ad45dc29964b4fc4481e Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 29 Jul 2018 16:47:39 +0200 Subject: [PATCH 14/40] =?UTF-8?q?[website]=20=E2=80=99Install=E2=80=99=20-?= =?UTF-8?q?>=20=E2=80=98How=20to=20use=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- website/templates/_scaffold.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/templates/_scaffold.html b/website/templates/_scaffold.html index 7acfb6b6..65b2fb7f 100644 --- a/website/templates/_scaffold.html +++ b/website/templates/_scaffold.html @@ -111,7 +111,7 @@ ga('send', 'pageview');