mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 18:15:55 +00:00
Merge branch 'bulgakovalexander-feature/var'
This commit is contained in:
commit
369518c92c
35 files changed
+545
-55
No files matched your search
@@ -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@"/>
|
||||
|
||||
@@ -154,6 +154,9 @@ such as converting the changelog into HTML, and creating javadoc.
|
||||
<antcall target="-integrateSnippet">
|
||||
<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>
|
||||
|
||||
@@ -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 -----
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class AllowHelper {
|
||||
private final static Set<String> allowable = new HashSet<String>(asList(
|
||||
"var"
|
||||
));
|
||||
|
||||
public static boolean isAllowable(String feature) {
|
||||
return allowable.contains(feature);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -95,12 +96,19 @@ public class HandlerUtil {
|
||||
return Singulars.autoSingularize(plural);
|
||||
}
|
||||
public static void handleFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key, String featureName) {
|
||||
boolean allowable = AllowHelper.isAllowable(featureName);
|
||||
|
||||
FlagUsageType fut = node.getAst().readConfiguration(key);
|
||||
|
||||
boolean allowed = !allowable || FlagUsageType.ALLOW == fut;
|
||||
if (!allowed) {
|
||||
node.addError("Use of " + featureName + " is disabled by default. Please use flag " + FlagUsageType.ALLOW + " to enable.");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class ValNullInit {
|
||||
void method() {
|
||||
final java.lang.Object x = null;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class VarInForOld {
|
||||
public void oldFor() {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class VarModifier {
|
||||
private String field = "";
|
||||
public void testComplex() {
|
||||
final char[] shouldBeFinalCharArray = field.toCharArray();
|
||||
char[] shouldBeCharArray = field.toCharArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
public class VarNullInit {
|
||||
void method() {
|
||||
java.lang.Object x = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import lombok.val;
|
||||
|
||||
class ValNullInit {
|
||||
ValNullInit() {
|
||||
super();
|
||||
}
|
||||
void method() {
|
||||
final @val java.lang.Object x = null;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import lombok.experimental.var;
|
||||
public class VarNullInit {
|
||||
public VarNullInit() {
|
||||
super();
|
||||
}
|
||||
void method() {
|
||||
@var java.lang.Object x = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import lombok.val;
|
||||
|
||||
class ValNullInit {
|
||||
void method() {
|
||||
val x = null;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
//CONF: lombok.var.flagUsage = ALLOW
|
||||
import lombok.experimental.var;
|
||||
|
||||
public class VarNullInit {
|
||||
void method() {
|
||||
var x = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
6 variable initializer is 'null'
|
||||
@@ -0,0 +1 @@
|
||||
6 variable initializer is 'null'
|
||||
@@ -0,0 +1,21 @@
|
||||
import java.util.ArrayList;
|
||||
import lombok.var;
|
||||
|
||||
public class ValExample {
|
||||
public String example() {
|
||||
ArrayList example = new ArrayList<String>();
|
||||
example.add("Hello, World!");
|
||||
final String foo = example.get(0);
|
||||
return foo.toLowerCase();
|
||||
}
|
||||
|
||||
public void example2() {
|
||||
ArrayList 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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.11.
|
||||
</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>Lombok will flag any usage of <code>var</code> as a error if not configured.</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, such as when the initializer expression is <code>null</code>, <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="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>
|
||||
</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>
|
||||
Reference in new issue
Block a user