diff options
45 files changed, 592 insertions, 68 deletions
diff --git a/buildScripts/eclipse-run-tests.template b/buildScripts/eclipse-run-tests.template index 530341ab..0c00c236 100644 --- a/buildScripts/eclipse-run-tests.template +++ b/buildScripts/eclipse-run-tests.template @@ -20,7 +20,7 @@ <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/lombok/@JAVAC_LOCATION@" path="3" type="2"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/lombok/lib/test/com.google.guava-guava.jar" path="3" type="2"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/lombok/lib/test/com.google.code.findbugs-findbugs.jar" path="3" type="2"/> "/> - <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="lombok"/> </runtimeClasspathEntry> "/> + <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="true" project="lombok"/> </runtimeClasspathEntry> "/> </listAttribute> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.@JAVA_VERSION@"/> diff --git a/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.20.xml b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.22.xml index f8ddcb51..85e2f9ef 100644 --- a/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.20.xml +++ b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.22.xml @@ -1,5 +1,5 @@ <ivy-module version="2.0"> - <info organisation="org.projectlombok" module="lombok.patcher" revision="0.20" publication="20150408000000"> + <info organisation="org.projectlombok" module="lombok.patcher" revision="0.22" publication="20161107000000"> <license name="MIT License" url="http://www.opensource.org/licenses/mit-license.php" /> <ivyauthor name="rzwitserloot" url="http://zwitserloot.com/" /> <ivyauthor name="rspilker" url="http://github.com/rspilker" /> @@ -9,6 +9,6 @@ <conf name="default" /> </configurations> <publications> - <artifact conf="default" url="https://projectlombok.org/downloads/lombok.patcher-0.20.jar" /> + <artifact conf="default" url="https://projectlombok.org/downloads/lombok.patcher-0.22.jar" /> </publications> </ivy-module> diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml index e0066ae4..3a851fcd 100644 --- a/buildScripts/ivy.xml +++ b/buildScripts/ivy.xml @@ -15,7 +15,7 @@ <conf name="javac7" /> </configurations> <dependencies> - <dependency org="org.projectlombok" name="lombok.patcher" rev="0.20" conf="buildBase->default; runtime->default" /> + <dependency org="org.projectlombok" name="lombok.patcher" rev="0.22" conf="buildBase->default; runtime->default" /> <dependency org="zwitserloot.com" name="cmdreader" rev="1.2" conf="buildBase->runtime; runtime" /> <dependency org="junit" name="junit" rev="4.8.2" conf="test->default; contrib->sources" /> diff --git a/buildScripts/website.ant.xml b/buildScripts/website.ant.xml index aae2285f..19b995d3 100644 --- a/buildScripts/website.ant.xml +++ b/buildScripts/website.ant.xml @@ -155,6 +155,9 @@ such as converting the changelog into HTML, and creating javadoc. <param name="transformationName" value="Singular-snippet" /> </antcall> <antcall target="-integrateSnippet"> + <param name="transformationName" value="experimental/var" /> + </antcall> + <antcall target="-integrateSnippet"> <param name="transformationName" value="experimental/Delegate" /> </antcall> <antcall target="-integrateSnippet"> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 89df8709..af6afad4 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -3,6 +3,8 @@ Lombok Changelog ### v1.16.11 "Edgy Guinea Pig" * v1.16.10 is the latest release +* FEATURE: `var` is the mutable sister of `val`. For now experimental, and opt-in using `ALLOW` in the flagUsage configuration key. Thanks for the contribution, Bulgakov Alexander. +* BUGFIX: Annotation Processors that use ecj internally (dagger) no longer give linkage errors [Issue #1218](https://github.com/rzwitserloot/lombok/issues/1218) * BUGFIX: `val` in lambda expressions now work as expected [Issue #911](https://github.com/rzwitserloot/lombok/issues/911) * PLATFORM: Red Hat JBoss Developer Studio is now correctly identified by the installer [Issue #1164](https://github.com/rzwitserloot/lombok/issues/1164) * BUGFIX: delombok: for-loops with initializers that are not local variables would be generated incorrectly [Issue #1076](https://github.com/rzwitserloot/lombok/issues/1076) diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 04decf69..132bde8d 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -283,7 +283,8 @@ public class ConfigurationKeys { * If set, <em>any</em> usage of {@code val} results in a warning / error. */ public static final ConfigurationKey<FlagUsageType> VAL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.val.flagUsage", "Emit a warning or error if 'val' is used.") {}; - + public static final ConfigurationKey<FlagUsageType> VAR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.var.flagUsage", "Emit a warning or error if 'var' is used.") {}; + // ##### Extern ##### // ----- Logging ----- diff --git a/src/core/lombok/core/configuration/AllowHelper.java b/src/core/lombok/core/configuration/AllowHelper.java new file mode 100644 index 00000000..3873b055 --- /dev/null +++ b/src/core/lombok/core/configuration/AllowHelper.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.core.configuration; + +import java.util.Collection; +import java.util.Collections; + +import lombok.ConfigurationKeys; + +public final class AllowHelper { + private final static Collection<? extends ConfigurationKey<?>> ALLOWABLE = Collections.singleton(ConfigurationKeys.VAR_FLAG_USAGE); + + private AllowHelper() { + // Prevent instantiation + } + + public static boolean isAllowable(ConfigurationKey<?> key) { + return ALLOWABLE.contains(key); + } +} diff --git a/src/core/lombok/core/configuration/FlagUsageType.java b/src/core/lombok/core/configuration/FlagUsageType.java index b7053b7c..8717c22b 100644 --- a/src/core/lombok/core/configuration/FlagUsageType.java +++ b/src/core/lombok/core/configuration/FlagUsageType.java @@ -23,5 +23,5 @@ package lombok.core.configuration; /** Used for lombok configuration to flag usages of certain lombok feature. */ public enum FlagUsageType { - WARNING, ERROR; + WARNING, ERROR, ALLOW; } diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index a9a4be78..ef4ac7d6 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -43,6 +43,7 @@ import lombok.core.AST; import lombok.core.AnnotationValues; import lombok.core.JavaIdentifiers; import lombok.core.LombokNode; +import lombok.core.configuration.AllowHelper; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; import lombok.experimental.Accessors; @@ -97,10 +98,14 @@ public class HandlerUtil { public static void handleFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key, String featureName) { FlagUsageType fut = node.getAst().readConfiguration(key); + if (fut == null && AllowHelper.isAllowable(key)) { + node.addError("Use of " + featureName + " is disabled by default. Please add '" + key.getKeyName() + " = " + FlagUsageType.ALLOW + "' to 'lombok.config' if you want to enable is."); + } + if (fut != null) { String msg = "Use of " + featureName + " is flagged according to lombok configuration."; if (fut == FlagUsageType.WARNING) node.addWarning(msg); - else node.addError(msg); + else if (fut == FlagUsageType.ERROR) node.addError(msg); } } diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index d4ae417c..d8901067 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 The Project Lombok Authors. + * Copyright (C) 2010-2016 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,8 @@ */ package lombok.eclipse.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.eclipse.handlers.EclipseHandlerUtil.typeMatches; import lombok.ConfigurationKeys; import lombok.val; import lombok.core.HandlerPriority; @@ -29,11 +30,14 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseASTAdapter; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; +import lombok.experimental.var; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ForStatement; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.mangosdk.spi.ProviderFor; /* @@ -44,8 +48,13 @@ import org.mangosdk.spi.ProviderFor; @HandlerPriority(65536) // 2^16; resolution needs to work, so if the RHS expression is i.e. a call to a generated getter, we have to run after that getter has been generated. public class HandleVal extends EclipseASTAdapter { @Override public void visitLocal(EclipseNode localNode, LocalDeclaration local) { - if (!EclipseHandlerUtil.typeMatches(val.class, localNode, local.type)) return; - handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + TypeReference type = local.type; + boolean isVal = typeMatches(val.class, localNode, type); + boolean isVar = typeMatches(var.class, localNode, type); + if (!(isVal || isVar)) return; + + if (isVal) handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + if (isVar) handleFlagUsage(localNode, ConfigurationKeys.VAR_FLAG_USAGE, "var"); boolean variableOfForEach = false; @@ -54,23 +63,30 @@ public class HandleVal extends EclipseASTAdapter { variableOfForEach = fs.elementVariable == local; } + String annotation = isVal ? "val" : "var"; if (local.initialization == null && !variableOfForEach) { - localNode.addError("'val' on a local variable requires an initializer expression"); + localNode.addError("'" + annotation + "' on a local variable requires an initializer expression"); return; } if (local.initialization instanceof ArrayInitializer) { - localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + localNode.addError("'" + annotation + "' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); return; } - if (localNode.directUp().get() instanceof ForStatement) { + if (isVal && localNode.directUp().get() instanceof ForStatement) { localNode.addError("'val' is not allowed in old-style for loops"); return; } if (local.initialization != null && local.initialization.getClass().getName().equals("org.eclipse.jdt.internal.compiler.ast.LambdaExpression")) { - localNode.addError("'val' is not allowed with lambda expressions."); + localNode.addError("'" + annotation + "' is not allowed with lambda expressions."); + return; + } + + if(isVar && local.initialization instanceof NullLiteral) { + localNode.addError("variable initializer is 'null'"); + return; } } } diff --git a/src/core/lombok/experimental/var.java b/src/core/lombok/experimental/var.java new file mode 100644 index 00000000..d8de8b19 --- /dev/null +++ b/src/core/lombok/experimental/var.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010-2013 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.experimental; + +/** + * like val but not final + */ +public @interface var { +} diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 337ab2d7..2976eabe 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 The Project Lombok Authors. + * Copyright (C) 2010-2016 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,11 +21,12 @@ */ package lombok.javac.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.javac.handlers.JavacHandlerUtil.*; import lombok.ConfigurationKeys; import lombok.val; import lombok.core.HandlerPriority; +import lombok.experimental.var; import lombok.javac.JavacASTAdapter; import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; @@ -42,6 +43,7 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; @@ -50,21 +52,31 @@ import com.sun.tools.javac.util.List; @HandlerPriority(65536) // 2^16; resolution needs to work, so if the RHS expression is i.e. a call to a generated getter, we have to run after that getter has been generated. @ResolutionResetNeeded public class HandleVal extends JavacASTAdapter { - @Override public void visitLocal(JavacNode localNode, JCVariableDecl local) { + + private static boolean eq(String typeTreeToString, String key) { + return (typeTreeToString.equals(key) || typeTreeToString.equals("lombok." + key)); + } + + @Override + public void visitLocal(JavacNode localNode, JCVariableDecl local) { JCTree typeTree = local.vartype; if (typeTree == null) return; String typeTreeToString = typeTree.toString(); - if (!typeTreeToString.equals("val") && !typeTreeToString.equals("lombok.val")) return; - if (!typeMatches(val.class, localNode, typeTree)) return; - - handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); - + + if (!(eq(typeTreeToString, "val") || eq(typeTreeToString, "var"))) return; + boolean isVal = typeMatches(val.class, localNode, typeTree); + boolean isVar = typeMatches(var.class, localNode, typeTree); + if (!(isVal || isVar)) return; + + if (isVal) handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + if (isVar) handleFlagUsage(localNode, ConfigurationKeys.VAR_FLAG_USAGE, "var"); + JCTree parentRaw = localNode.directUp().get(); - if (parentRaw instanceof JCForLoop) { + if (isVal && parentRaw instanceof JCForLoop) { localNode.addError("'val' is not allowed in old-style for loops"); return; } - + JCExpression rhsOfEnhancedForLoop = null; if (local.init == null) { if (parentRaw instanceof JCEnhancedForLoop) { @@ -72,21 +84,26 @@ public class HandleVal extends JavacASTAdapter { if (efl.var == local) rhsOfEnhancedForLoop = efl.expr; } } - + + final String annotation = typeTreeToString; if (rhsOfEnhancedForLoop == null && local.init == null) { - localNode.addError("'val' on a local variable requires an initializer expression"); + localNode.addError("'" + annotation + "' on a local variable requires an initializer expression"); return; + } - + if (local.init instanceof JCNewArray && ((JCNewArray)local.init).elemtype == null) { - localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + localNode.addError("'" + annotation + "' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); return; } - - if (localNode.shouldDeleteLombokAnnotations()) JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, "lombok.val"); - - local.mods.flags |= Flags.FINAL; - + + if (localNode.shouldDeleteLombokAnnotations()) { + JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, val.class.getName()); + JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, var.class.getName()); + } + + if (isVal) local.mods.flags |= Flags.FINAL; + if (!localNode.shouldDeleteLombokAnnotations()) { JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeTree, localNode.getContext()); local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); @@ -102,6 +119,9 @@ public class HandleVal extends JavacASTAdapter { try { if (rhsOfEnhancedForLoop == null) { if (local.init.type == null) { + if (isVar && local.init instanceof JCLiteral && ((JCLiteral) local.init).value == null) { + localNode.addError("variable initializer is 'null'"); + } JavacResolution resolver = new JavacResolution(localNode.getContext()); try { type = ((JCExpression) resolver.resolveMethodMember(localNode).get(local.init)).type; @@ -149,7 +169,7 @@ public class HandleVal extends JavacASTAdapter { } localNode.getAst().setChanged(); } catch (JavacResolution.TypeNotConvertibleException e) { - localNode.addError("Cannot use 'val' here because initializer expression does not have a representable type: " + e.getMessage()); + localNode.addError("Cannot use '" + annotation + "' here because initializer expression does not have a representable type: " + e.getMessage()); local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); } } catch (RuntimeException e) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 7c538b6f..4b18dc0f 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -24,11 +24,14 @@ package lombok.eclipse.agent; import static lombok.patcher.scripts.ScriptBuilder.*; import java.lang.instrument.Instrumentation; +import java.net.URLClassLoader; +import java.security.ProtectionDomain; import java.util.Collection; import java.util.Collections; import java.util.List; import lombok.core.AgentLauncher; +import lombok.patcher.Filter; import lombok.patcher.Hook; import lombok.patcher.MethodTarget; import lombok.patcher.ScriptManager; @@ -74,6 +77,15 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { private static void registerPatchScripts(Instrumentation instrumentation, boolean reloadExistingClasses, boolean ecjOnly, Class<?> launchingContext) { ScriptManager sm = new ScriptManager(); sm.registerTransformer(instrumentation); + sm.setFilter(new Filter() { + @Override public boolean shouldTransform(ClassLoader loader, String className, Class<?> classBeingDefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + if (!(loader instanceof URLClassLoader)) return true; + ClassLoader parent = loader.getParent(); + if (parent == null) return true; + return !parent.getClass().getName().startsWith("org.eclipse.jdt.apt.core.internal.AnnotationProcessorFactoryLoader"); + } + }); + final boolean forceBaseResourceNames = !"".equals(System.getProperty("shadow.override.lombok", "")); sm.setTransplantMapper(new TransplantMapper() { public String mapResourceName(int classFileFormatVersion, String resourceName) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 2b8dfbaa..e4dd7b26 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -21,11 +21,6 @@ */ package lombok.eclipse.agent; -import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import static lombok.eclipse.Eclipse.*; - -import java.lang.reflect.Field; - import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; @@ -43,6 +38,11 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import java.lang.reflect.Field; + +import static lombok.eclipse.Eclipse.poss; +import static lombok.eclipse.handlers.EclipseHandlerUtil.makeType; + public class PatchVal { // This is half of the work for 'val' support - the other half is in PatchValEclipse. This half is enough for ecj. @@ -84,31 +84,44 @@ public class PatchVal { return true; } - public static boolean couldBeVal(TypeReference ref) { + public static boolean couldBe(String key, TypeReference ref) { + String[] keyParts = key.split("\\."); if (ref instanceof SingleTypeReference) { char[] token = ((SingleTypeReference)ref).token; - return matches("val", token); + return matches(keyParts[keyParts.length - 1], token); } if (ref instanceof QualifiedTypeReference) { char[][] tokens = ((QualifiedTypeReference)ref).tokens; - if (tokens == null || tokens.length != 2) return false; - return matches("lombok", tokens[0]) && matches("val", tokens[1]); + if (keyParts.length != tokens.length) return false; + for(int i = 0; i < tokens.length; ++i) { + String part = keyParts[i]; + char[] token = tokens[i]; + if (!matches(part, token)) return false; + } + return true; } return false; } - - private static boolean isVal(TypeReference ref, BlockScope scope) { - if (!couldBeVal(ref)) return false; - + + private static boolean is(TypeReference ref, BlockScope scope, String key) { + if (!couldBe(key, ref)) return false; + TypeBinding resolvedType = ref.resolvedType; if (resolvedType == null) resolvedType = ref.resolveType(scope, false); if (resolvedType == null) return false; char[] pkg = resolvedType.qualifiedPackageName(); char[] nm = resolvedType.qualifiedSourceName(); - return matches("lombok", pkg) && matches("val", nm); + int pkgFullLength = pkg.length > 0 ? pkg.length + 1: 0; + char[] fullName = new char[pkgFullLength + nm.length]; + if(pkg.length > 0) { + System.arraycopy(pkg, 0, fullName, 0, pkg.length); + fullName[pkg.length] = '.'; + } + System.arraycopy(nm, 0, fullName, pkgFullLength, nm.length); + return matches(key, fullName); } public static final class Reflection { @@ -132,13 +145,17 @@ public class PatchVal { if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false; boolean decomponent = false; - if (!isVal(local.type, scope)) 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")) { - if (st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && - st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement")) return false; + 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"); + if (valInForStatement) return false; break; } } @@ -187,23 +204,33 @@ public class PatchVal { } } - 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)); return false; } + private static boolean isVar(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.experimental.var"); + } + + private static boolean isVal(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.val"); + } + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { if (forEach.elementVariable == null) return false; - if (!isVal(forEach.elementVariable.type, scope)) return false; + boolean val = isVal(forEach.elementVariable, scope); + boolean var = isVar(forEach.elementVariable, scope); + if (!(val || var)) return false; TypeBinding component = getForEachComponentType(forEach.collection, scope); if (component == null) return false; TypeReference replacement = makeType(component, forEach.elementVariable.type, false); - forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; + 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)); diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index 7d5f36f4..505eb767 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -47,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; 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; @@ -65,7 +66,9 @@ public class PatchValEclipse { ForeachStatement foreachDecl = (ForeachStatement) astStack[astPtr]; ASTNode init = foreachDecl.collection; if (init == null) return; - if (foreachDecl.elementVariable == null || !PatchVal.couldBeVal(foreachDecl.elementVariable.type)) return; + boolean val = couldBeVal(foreachDecl.elementVariable.type); + boolean var = couldBeVar(foreachDecl.elementVariable.type); + if (foreachDecl.elementVariable == null || !(val || var)) return; try { if (Reflection.iterableCopyField != null) Reflection.iterableCopyField.set(foreachDecl.elementVariable, init); @@ -88,7 +91,9 @@ public class PatchValEclipse { if (!(variableDecl instanceof LocalDeclaration)) return; ASTNode init = variableDecl.initialization; if (init == null) return; - if (!PatchVal.couldBeVal(variableDecl.type)) return; + boolean val = couldBeVal(variableDecl.type); + boolean var = couldBeVar(variableDecl.type); + if (!(val || var)) return; try { if (Reflection.initCopyField != null) Reflection.initCopyField.set(variableDecl, init); @@ -97,6 +102,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVar(TypeReference type) { + return PatchVal.couldBe("lombok.experimental.var", type); + } + public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, SingleVariableDeclaration out, LocalDeclaration in) { @SuppressWarnings("unchecked") List<IExtendedModifier> modifiers = out.modifiers(); addFinalAndValAnnotationToModifierList(converter, modifiers, out.getAST(), in); @@ -115,7 +124,7 @@ public class PatchValEclipse { Annotation valAnnotation = null; for (Annotation ann : in.annotations) { - if (PatchVal.couldBeVal(ann.type)) { + if (couldBeVal(ann.type)) { found = true; valAnnotation = ann; break; @@ -167,6 +176,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVal(TypeReference type) { + return PatchVal.couldBe("lombok.val", type); + } + public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) { Modifier modifier = null; try { diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index f564d0dc..d044a39f 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -57,10 +57,16 @@ public abstract class AbstractRunTests { public final FileTester createTester(final DirectoryRunner.TestParams params, final File file) throws IOException { ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys(); - final LombokTestSource sourceDirectives = LombokTestSource.readDirectives(file); - if (sourceDirectives.isIgnore()) return null; - if (!sourceDirectives.versionWithinLimit(params.getVersion())) return null; - if (!sourceDirectives.versionWithinLimit(getClasspathVersion())) return null; + AssertionError directiveFailure = null; + LombokTestSource sourceDirectives = null; + try { + sourceDirectives = LombokTestSource.readDirectives(file); + if (sourceDirectives.isIgnore()) return null; + if (!sourceDirectives.versionWithinLimit(params.getVersion())) return null; + if (!sourceDirectives.versionWithinLimit(getClasspathVersion())) return null; + } catch (AssertionError ae) { + directiveFailure = ae; + } String fileName = file.getName(); final LombokTestSource expected = LombokTestSource.read(params.getAfterDirectory(), params.getMessagesDirectory(), fileName); @@ -68,23 +74,26 @@ public abstract class AbstractRunTests { if (expected.isIgnore()) return null; if (!expected.versionWithinLimit(params.getVersion())) return null; + final LombokTestSource sourceDirectives_ = sourceDirectives; + final AssertionError directiveFailure_ = directiveFailure; return new FileTester() { @Override public void runTest() throws Throwable { + if (directiveFailure_ != null) throw directiveFailure_; LinkedHashSet<CompilerMessage> messages = new LinkedHashSet<CompilerMessage>(); StringWriter writer = new StringWriter(); LombokConfiguration.overrideConfigurationResolverFactory(new ConfigurationResolverFactory() { @Override public ConfigurationResolver createResolver(AST<?, ?, ?> ast) { - return sourceDirectives.getConfiguration(); + return sourceDirectives_.getConfiguration(); } }); - boolean changed = transformCode(messages, writer, file, sourceDirectives.getSpecifiedEncoding(), sourceDirectives.getFormatPreferences()); - boolean forceUnchanged = sourceDirectives.forceUnchanged() || sourceDirectives.isSkipCompareContent(); + boolean changed = transformCode(messages, writer, file, sourceDirectives_.getSpecifiedEncoding(), sourceDirectives_.getFormatPreferences()); + boolean forceUnchanged = sourceDirectives_.forceUnchanged() || sourceDirectives_.isSkipCompareContent(); if (params.expectChanges() && !forceUnchanged && !changed) messages.add(new CompilerMessage(-1, -1, true, "not flagged modified")); if (!params.expectChanges() && changed) messages.add(new CompilerMessage(-1, -1, true, "unexpected modification")); - compare(file.getName(), expected, writer.toString(), messages, params.printErrors(), sourceDirectives.isSkipCompareContent() || expected.isSkipCompareContent()); + compare(file.getName(), expected, writer.toString(), messages, params.printErrors(), sourceDirectives_.isSkipCompareContent() || expected.isSkipCompareContent()); } }; } diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index cd7cd166..16f9f49f 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -130,7 +130,7 @@ public class LombokTestSource { private static final Pattern IGNORE_PATTERN = Pattern.compile("^\\s*ignore\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern UNCHANGED_PATTERN = Pattern.compile("^\\s*unchanged\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); - private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?content\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); + private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?contents?\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private LombokTestSource(File file, String content, List<CompilerMessageMatcher> messages, List<String> directives) { this.file = file; diff --git a/test/transform/resource/after-delombok/ValNullInit.java b/test/transform/resource/after-delombok/ValNullInit.java new file mode 100644 index 00000000..f0834a63 --- /dev/null +++ b/test/transform/resource/after-delombok/ValNullInit.java @@ -0,0 +1,5 @@ +class ValNullInit { + void method() { + final java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarComplex.java b/test/transform/resource/after-delombok/VarComplex.java new file mode 100644 index 00000000..10b33943 --- /dev/null +++ b/test/transform/resource/after-delombok/VarComplex.java @@ -0,0 +1,20 @@ +public class VarComplex { + private String field = ""; + private static final int CONSTANT = 20; + public void testComplex() { + char[] shouldBeCharArray = field.toCharArray(); + int shouldBeInt = CONSTANT; + java.lang.Object lock = new Object(); + synchronized (lock) { + int field = 20; //Shadowing + int inner = 10; + switch (field) { + case 5: + char[] shouldBeCharArray2 = shouldBeCharArray; + int innerInner = inner; + + } + } + java.lang.String shouldBeString = field; //Unshadowing + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarInFor.java b/test/transform/resource/after-delombok/VarInFor.java new file mode 100644 index 00000000..363aeeff --- /dev/null +++ b/test/transform/resource/after-delombok/VarInFor.java @@ -0,0 +1,9 @@ +public class VarInFor { + public void enhancedFor() { + int[] list = new int[] {1, 2}; + for (int shouldBeInt : list) { + System.out.println(shouldBeInt); + int shouldBeInt2 = shouldBeInt; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarInForOld.java b/test/transform/resource/after-delombok/VarInForOld.java new file mode 100644 index 00000000..bb510c0b --- /dev/null +++ b/test/transform/resource/after-delombok/VarInForOld.java @@ -0,0 +1,7 @@ +public class VarInForOld { + public void oldFor() { + for (int i = 0; i < 100; ++i) { + System.out.println(i); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarModifier.java b/test/transform/resource/after-delombok/VarModifier.java new file mode 100644 index 00000000..9838cdf7 --- /dev/null +++ b/test/transform/resource/after-delombok/VarModifier.java @@ -0,0 +1,7 @@ +public class VarModifier { + private String field = ""; + public void testComplex() { + final char[] shouldBeFinalCharArray = field.toCharArray(); + char[] shouldBeCharArray = field.toCharArray(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarNullInit.java b/test/transform/resource/after-delombok/VarNullInit.java new file mode 100644 index 00000000..8ec2ea73 --- /dev/null +++ b/test/transform/resource/after-delombok/VarNullInit.java @@ -0,0 +1,6 @@ + +public class VarNullInit { + void method() { + java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValNullInit.java b/test/transform/resource/after-ecj/ValNullInit.java new file mode 100644 index 00000000..bd89c023 --- /dev/null +++ b/test/transform/resource/after-ecj/ValNullInit.java @@ -0,0 +1,10 @@ +import lombok.val; + +class ValNullInit { + ValNullInit() { + super(); + } + void method() { + final @val java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarComplex.java b/test/transform/resource/after-ecj/VarComplex.java new file mode 100644 index 00000000..10c456eb --- /dev/null +++ b/test/transform/resource/after-ecj/VarComplex.java @@ -0,0 +1,26 @@ +import lombok.experimental.var; +public class VarComplex { + private String field = ""; + private static final int CONSTANT = 20; + <clinit>() { + } + public VarComplex() { + super(); + } + public void testComplex() { + @var char[] shouldBeCharArray = field.toCharArray(); + @var int shouldBeInt = CONSTANT; + @var java.lang.Object lock = new Object(); + synchronized (lock) + { + @var int field = 20; + @var int inner = 10; + switch (field) { + case 5 : + @var char[] shouldBeCharArray2 = shouldBeCharArray; + @var int innerInner = inner; + } + } + @var java.lang.String shouldBeString = field; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarInFor.java b/test/transform/resource/after-ecj/VarInFor.java new file mode 100644 index 00000000..0192aaed --- /dev/null +++ b/test/transform/resource/after-ecj/VarInFor.java @@ -0,0 +1,14 @@ +import lombok.experimental.var; +public class VarInFor { + public VarInFor() { + super(); + } + public void enhancedFor() { + int[] list = new int[]{1, 2}; + for (@var int shouldBeInt : list) + { + System.out.println(shouldBeInt); + @var int shouldBeInt2 = shouldBeInt; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarInForOld.java b/test/transform/resource/after-ecj/VarInForOld.java new file mode 100644 index 00000000..98fedf03 --- /dev/null +++ b/test/transform/resource/after-ecj/VarInForOld.java @@ -0,0 +1,12 @@ +import lombok.experimental.var; +public class VarInForOld { + public VarInForOld() { + super(); + } + public void oldFor() { + for (@var int i = 0;; (i < 100); ++ i) + { + System.out.println(i); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarModifier.java b/test/transform/resource/after-ecj/VarModifier.java new file mode 100644 index 00000000..d11142ca --- /dev/null +++ b/test/transform/resource/after-ecj/VarModifier.java @@ -0,0 +1,12 @@ +import lombok.experimental.var; +public class VarModifier { + private String field = ""; + public VarModifier() { + super(); + } + public void testComplex() { + final @var char[] shouldBeFinalCharArray = field.toCharArray(); + @var char[] shouldBeCharArray = field.toCharArray(); + + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarNullInit.java b/test/transform/resource/after-ecj/VarNullInit.java new file mode 100644 index 00000000..3eb2d506 --- /dev/null +++ b/test/transform/resource/after-ecj/VarNullInit.java @@ -0,0 +1,9 @@ +import lombok.experimental.var; +public class VarNullInit { + public VarNullInit() { + super(); + } + void method() { + @var java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValNullInit.java b/test/transform/resource/before/ValNullInit.java new file mode 100644 index 00000000..649bc0cd --- /dev/null +++ b/test/transform/resource/before/ValNullInit.java @@ -0,0 +1,7 @@ +import lombok.val; + +class ValNullInit { + void method() { + val x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarComplex.java b/test/transform/resource/before/VarComplex.java new file mode 100644 index 00000000..bfaa8804 --- /dev/null +++ b/test/transform/resource/before/VarComplex.java @@ -0,0 +1,23 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarComplex { + private String field = ""; + private static final int CONSTANT = 20; + + public void testComplex() { + var shouldBeCharArray = field.toCharArray(); + var shouldBeInt = CONSTANT; + var lock = new Object(); + synchronized (lock) { + var field = 20; //Shadowing + var inner = 10; + switch (field) { + case 5: + var shouldBeCharArray2 = shouldBeCharArray; + var innerInner = inner; + } + } + var shouldBeString = field; //Unshadowing + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarInFor.java b/test/transform/resource/before/VarInFor.java new file mode 100644 index 00000000..cc8c387e --- /dev/null +++ b/test/transform/resource/before/VarInFor.java @@ -0,0 +1,12 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarInFor { + public void enhancedFor() { + int[] list = new int[] {1, 2}; + for (var shouldBeInt : list) { + System.out.println(shouldBeInt); + var shouldBeInt2 = shouldBeInt; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarInForOld.java b/test/transform/resource/before/VarInForOld.java new file mode 100644 index 00000000..f90aba7f --- /dev/null +++ b/test/transform/resource/before/VarInForOld.java @@ -0,0 +1,10 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarInForOld { + public void oldFor() { + for (var i = 0; i < 100; ++i) { + System.out.println(i); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarModifier.java b/test/transform/resource/before/VarModifier.java new file mode 100644 index 00000000..7250c1c5 --- /dev/null +++ b/test/transform/resource/before/VarModifier.java @@ -0,0 +1,11 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarModifier { + private String field = ""; + + public void testComplex() { + final var shouldBeFinalCharArray = field.toCharArray(); + var shouldBeCharArray = field.toCharArray(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarNullInit.java b/test/transform/resource/before/VarNullInit.java new file mode 100644 index 00000000..efdc9d9e --- /dev/null +++ b/test/transform/resource/before/VarNullInit.java @@ -0,0 +1,8 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarNullInit { + void method() { + var x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarWarning.java b/test/transform/resource/before/VarWarning.java new file mode 100644 index 00000000..85559587 --- /dev/null +++ b/test/transform/resource/before/VarWarning.java @@ -0,0 +1,10 @@ +//CONF: lombok.var.flagUsage = WARNING +//skip compare contents +import lombok.experimental.var; + +public class VarWarning { + public void isOkay() { + var x = "Warning"; + x.toLowerCase(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/VarNullInit.java.messages b/test/transform/resource/messages-delombok/VarNullInit.java.messages new file mode 100644 index 00000000..190ab7c4 --- /dev/null +++ b/test/transform/resource/messages-delombok/VarNullInit.java.messages @@ -0,0 +1 @@ +6 variable initializer is 'null'
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/VarWarning.java.messages b/test/transform/resource/messages-delombok/VarWarning.java.messages new file mode 100644 index 00000000..48c89581 --- /dev/null +++ b/test/transform/resource/messages-delombok/VarWarning.java.messages @@ -0,0 +1 @@ +7 Use of var is flagged according to lombok configuration
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/VarNullInit.java.messages b/test/transform/resource/messages-ecj/VarNullInit.java.messages new file mode 100644 index 00000000..190ab7c4 --- /dev/null +++ b/test/transform/resource/messages-ecj/VarNullInit.java.messages @@ -0,0 +1 @@ +6 variable initializer is 'null'
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/VarWarning.java.messages b/test/transform/resource/messages-ecj/VarWarning.java.messages new file mode 100644 index 00000000..48c89581 --- /dev/null +++ b/test/transform/resource/messages-ecj/VarWarning.java.messages @@ -0,0 +1 @@ +7 Use of var is flagged according to lombok configuration
\ No newline at end of file diff --git a/usage_examples/experimental/varExample_post.jpage b/usage_examples/experimental/varExample_post.jpage new file mode 100644 index 00000000..41c022d3 --- /dev/null +++ b/usage_examples/experimental/varExample_post.jpage @@ -0,0 +1,21 @@ +import java.util.ArrayList; +import lombok.var; + +public class ValExample { + public String example() { + ArrayList<String> example = new ArrayList<String>(); + example.add("Hello, World!"); + final String foo = example.get(0); + return foo.toLowerCase(); + } + + public void example2() { + ArrayList<String> list = new ArrayList<String>(); + list.add("zero"); + list.add("one"); + list.add("two"); + for(int i = 0; i < list.size(); ++i) { + System.out.printf("%d: %s\n", i, list.get(i)); + } + } +} diff --git a/usage_examples/experimental/varExample_pre.jpage b/usage_examples/experimental/varExample_pre.jpage new file mode 100644 index 00000000..0786c0df --- /dev/null +++ b/usage_examples/experimental/varExample_pre.jpage @@ -0,0 +1,21 @@ +import java.util.ArrayList; +import lombok.var; + +public class ValExample { + public String example() { + var example = new ArrayList<String>(); + example.add("Hello, World!"); + final var foo = example.get(0); + return foo.toLowerCase(); + } + + public void example2() { + var list = new ArrayList<String>(); + list.add("zero"); + list.add("one"); + list.add("two"); + for(var i = 0; i < list.size(); ++i) { + System.out.printf("%d: %s\n", i, list.get(i)); + } + } +} diff --git a/website/features/experimental/Accessors.html b/website/features/experimental/Accessors.html index 434cbdbe..909c0873 100644 --- a/website/features/experimental/Accessors.html +++ b/website/features/experimental/Accessors.html @@ -97,7 +97,7 @@ </div> </div> <div class="footer"> - <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <a href="ExtensionMethod.html">Next feature (@ExtensionMethod)</a><br /> + <a href="index.html">Back to experimental features</a> | <a href="var.html">Previous feature (var)</a> | <a href="ExtensionMethod.html">Next feature (@ExtensionMethod)</a><br /> <a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2016 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> </div> <div style="clear: both;"></div> diff --git a/website/features/experimental/index.html b/website/features/experimental/index.html index f3893674..4a6d12bb 100644 --- a/website/features/experimental/index.html +++ b/website/features/experimental/index.html @@ -22,6 +22,8 @@ Features that receive positive community feedback and which seem to produce clean, flexible code will eventually become accepted as a core feature and move out of the experimental package. <dl> + <dt><a href="var.html"><code>@var</code></a></dt> + <dd>The same as @val but modifiable.</dd> <dt><a href="Accessors.html"><code>@Accessors</code></a></dt> <dd>A more fluent API for getters and setters.</dd> <dt><a href="ExtensionMethod.html"><code>@ExtensionMethod</code></a></dt> diff --git a/website/features/experimental/var.html b/website/features/experimental/var.html new file mode 100644 index 00000000..dde9c35e --- /dev/null +++ b/website/features/experimental/var.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<html><head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="stylesheet" type="text/css" href="../../logi/reset.css" /> + <link rel="stylesheet" type="text/css" href="../features.css" /> + <link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon" /> + <meta name="description" content="Spice up your java" /> + <title>EXPERIMENTAL – @var</title> +</head><body><div id="pepper"> + <div class="minimumHeight"></div> + <div class="meat"> + <div class="header"><a href="../../index.html">Project Lombok</a></div> + <h1>@var</h1> + <div class="byline">Modifiable local variables with a type inferred by assigning value.</div> + <div class="since"> + <h3>Since</h3> + <p> + @var was introduced as experimental feature in lombok v1.16.12. + </p> + </div> + <div class="experimental"> + <h3>Experimental</h3> + <p> + Experimental because: + <ul> + <li>This feature is very controversial.</li> + <li>There is <a href="http://openjdk.java.net/jeps/286">JEP 286</a> that should make the @var obsolete.</li> + </ul>Current status: <em>uncertain</em> - Currently we feel this feature cannot move out of experimental status. + </div> + <div class="overview"> + <h3>Overview</h3> + <p> + The <code>@var</code> has the same mission as the <a href="../val.html">@val</a> annotation but modifable. + </p> + </div> + <div class="snippets"> + <div class="pre"> + <h3>With Lombok</h3> + <div class="snippet">@HTML_PRE@</div> + </div> + <div class="sep"></div> + <div class="post"> + <h3>Vanilla Java</h3> + <div class="snippet">@HTML_POST@</div> + </div> + </div> + <div style="clear: left;"></div> + <div class="overview confKeys"> + <h3>Supported configuration keys:</h3> + <dl> + <dt><code>lombok.val.flagUsage</code> = [<code>allow</code>] (default: not set)</dt> + <dd><strong>Lombok will flag any usage of <code>var</code> as an error if not configured.</strong></dd> + </dl> + </div> + <div class="overview"> + <h3>Small print</h3><div class="smallprint"> + <p> + For compound types, the most common superclass is inferred, not any shared interfaces. For example, <code>bool ? new HashSet() : new ArrayList()</code> + is an expression with a compound type: The result is both <code>AbstractCollection</code> as well as <code>Serializable</code>. The type inferred will be + <code>AbstractCollection</code>, as that is a class, whereas <code>Serializable</code> is an interface. + </p><p> + In ambiguous cases, <code>java.lang.Object</code> is inferred. + </p> + </div> + </div> + <div class="footer"> + <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <a href="Accessors.html">Next feature (@Accessors)</a><br /> + <a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2016 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> + </div> + <div style="clear: both;"></div> + </div> +</div> +<script type="text/javascript"> + var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); + document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); +</script> +<script type="text/javascript"> + try { + var pageTracker = _gat._getTracker("UA-9884254-1"); + pageTracker._trackPageview(); + } catch(err) {} +</script> +</body></html> |