aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2010-11-08 22:32:22 +0100
committerReinier Zwitserloot <reinier@zwitserloot.com>2010-11-08 22:52:07 +0100
commitcc60afa1eb4b14998e72c4fd5adf9def32e0e0f8 (patch)
treecae9a00aa7e5f8cfa08adfe22f3da98c5e0fcb4a /src/core
parentdee834a39780f61a0357c42f61592cd3c3598bd3 (diff)
downloadlombok-cc60afa1eb4b14998e72c4fd5adf9def32e0e0f8.tar.gz
lombok-cc60afa1eb4b14998e72c4fd5adf9def32e0e0f8.tar.bz2
lombok-cc60afa1eb4b14998e72c4fd5adf9def32e0e0f8.zip
'val' now also works in foreach loops, on both javac and ecj / eclipse.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/lombok/eclipse/handlers/HandleVal.java10
-rw-r--r--src/core/lombok/javac/JavacResolution.java121
-rw-r--r--src/core/lombok/javac/handlers/HandleVal.java18
3 files changed, 37 insertions, 112 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java
index 6fa39b10..b3cfa879 100644
--- a/src/core/lombok/eclipse/handlers/HandleVal.java
+++ b/src/core/lombok/eclipse/handlers/HandleVal.java
@@ -26,6 +26,7 @@ import lombok.eclipse.EclipseASTVisitor;
import lombok.eclipse.EclipseNode;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+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.mangosdk.spi.ProviderFor;
@@ -41,7 +42,14 @@ public class HandleVal extends EclipseASTAdapter {
if (token == null || token.length != 3) return;
else if (token[0] != 'v' || token[1] != 'a' || token[2] != 'l') return;
- if (local.initialization == null) {
+ boolean variableOfForEach = false;
+
+ if (localNode.directUp().get() instanceof ForeachStatement) {
+ ForeachStatement fs = (ForeachStatement) localNode.directUp().get();
+ variableOfForEach = fs.elementVariable == local;
+ }
+
+ if (local.initialization == null && !variableOfForEach) {
localNode.addError("'val' on a local variable requires an initializer expression");
}
diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java
index 14de1ff8..e0eb436d 100644
--- a/src/core/lombok/javac/JavacResolution.java
+++ b/src/core/lombok/javac/JavacResolution.java
@@ -12,11 +12,13 @@ import javax.tools.DiagnosticListener;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
+import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type.ArrayType;
import com.sun.tools.javac.code.Type.CapturedType;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTags;
+import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.comp.Attr;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Enter;
@@ -234,64 +236,11 @@ public class JavacResolution {
if (copyAt != null) return;
copyAt = tree;
}
+
+ @Override public void visitTree(JCTree that) {
+ }
}
-// /**
-// * The {@code Env} object primarily tracks legal symbol names. i.e. its the lexical scope. To build it, we need to go from the top and drill down to the current node,
-// * updating the {@code Env} object at each step. This TreeVisitor does that. Requires {@code enterTrees} to be called first (this is done before processors run, normally).
-// */
-// private static final class EnvChainer extends JCTree.Visitor {
-// private Env<AttrContext> env = null;
-// private Enter enter;
-// private MemberEnter memberEnter;
-// private Attr attr;
-// private JCTree target;
-// private boolean blocksAreInitializers;
-//
-// EnvChainer(Context context) {
-// this.enter = Enter.instance(context);
-// this.memberEnter = MemberEnter.instance(context);
-// this.attr = Attr.instance(context);
-// }
-//
-// Env<AttrContext> get() {
-// return env;
-// }
-//
-// @Override public void visitTopLevel(JCCompilationUnit tree) {
-// env = enter.getTopLevelEnv(tree);
-// }
-//
-// @Override public void visitClassDef(JCClassDecl tree) {
-// // The commented out one leaves the 'lint' field unset, which causes NPEs during attrib. So, we use the other one.
-// //env = enter.classEnv((JCClassDecl) tree, env);
-// env = enter.getClassEnv(tree.sym);
-// blocksAreInitializers = true;
-// }
-//
-// @Override public void visitMethodDef(JCMethodDecl tree) {
-// env = memberEnter.getMethodEnv(tree, env);
-// blocksAreInitializers = false;
-// if (tree.body != null) visitBlock(tree.body);
-// }
-//
-// @Override public void visitBlock(JCBlock tree) {
-// if (blocksAreInitializers) attr.attribStat(tree, env);
-// for (JCStatement stat : tree.stats) {
-// if (stat == target) return;
-// attr.attribStat(stat, env);
-// }
-// }
-//
-// @Override public void visitTree(JCTree tree) {
-// // Do nothing
-// }
-//
-// public void setTarget(JCTree target) {
-// this.target = target;
-// }
-// };
-
public Map<JCTree, JCTree> resolve(JavacNode node) {
ArrayDeque<JCTree> stack = new ArrayDeque<JCTree>();
@@ -325,58 +274,26 @@ public class JavacResolution {
else throw new IllegalStateException("Called with something that isn't a block, method decl, or variable decl");
}
-// public void resolveUpTo(JavacNode statementNode) {
-// ArrayDeque<JCTree> stack = new ArrayDeque<JCTree>();
-//
-// {
-// JavacNode n = statementNode;
-// while (n != null) {
-// stack.push(n.get());
-// n = n.up();
-// }
-// }
-//
-// logDisabler.disableLoggers();
-// try {
-// JCTree tree = stack.isEmpty() ? null : stack.pop();
-// while (!stack.isEmpty()) {
-// JCTree target = stack.pop();
-// envChainer.setTarget(target);
-// tree.accept(envChainer);
-// tree = target;
-// }
-// if (tree != null) {
-// envChainer.setTarget(null);
-// tree.accept(envChainer);
-// }
-//
-//// System.out.println("ATTRIBSTAT: " + attr.attribStat(statementNode.get(), envChainer.get()));
-//// if (statementNode.get() instanceof JCVariableDecl) {
-//// System.out.println("Force-tribbing expr");
-//// JCExpression init = ((JCVariableDecl)statementNode.get()).init;
-//// System.out.println("ATTRIBEXPR: " + attr.attribExpr(init, envChainer.get(), Type.noType));
-//// System.out.println("TYPE: " + ((JCVariableDecl)statementNode.get()).init.type);
-//// }
-// } finally {
-// logDisabler.enableLoggers();
-// }
-// }
-//
-// public void resolveExpr(JCExpression expr) {
-// logDisabler.disableLoggers();
-// try {
-// attr.attribExpr(expr, envChainer.get(), Type.noType);
-// } finally {
-// logDisabler.enableLoggers();
-// }
-// }
-
public static class TypeNotConvertibleException extends Exception {
public TypeNotConvertibleException(String msg) {
super(msg);
}
}
+ public static Type ifTypeIsIterableToComponent(Type type, JavacAST ast) {
+ Types types = Types.instance(ast.getContext());
+ Symtab syms = Symtab.instance(ast.getContext());
+ Type boundType = types.upperBound(type);
+ Type elemTypeIfArray = types.elemtype(boundType);
+ if (elemTypeIfArray != null) return elemTypeIfArray;
+
+ Type base = types.asSuper(boundType, syms.iterableType.tsym);
+ if (base == null) return syms.objectType;
+
+ List<Type> iterableParams = base.allparams();
+ return iterableParams.isEmpty() ? syms.objectType : types.upperBound(iterableParams.head);
+ }
+
public static JCExpression typeToJCTree(Type type, TreeMaker maker, JavacAST ast) throws TypeNotConvertibleException {
return typeToJCTree(type, maker, ast, false);
}
diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java
index 7161a7c3..5da6fec0 100644
--- a/src/core/lombok/javac/handlers/HandleVal.java
+++ b/src/core/lombok/javac/handlers/HandleVal.java
@@ -64,7 +64,6 @@ public class HandleVal extends JavacASTAdapter {
}
local.mods.flags |= Flags.FINAL;
- JCExpression oldVarType = local.vartype;
local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());
Type type;
@@ -89,25 +88,26 @@ public class HandleVal extends JavacASTAdapter {
JCExpression replacement;
if (rhsOfEnhancedForLoop != null) {
- localNode.addError("For now 'val' cannot be used in enhanced for loops. Fixing this is a high priority lombok issue though!");
- return;
- // TODO: Fix enhanced for loops - then uncomment a bunch of lines in test/transform/resource/*/ValInFor.java
+ Type componentType = JavacResolution.ifTypeIsIterableToComponent(type, localNode.getAst());
+ if (componentType == null) replacement = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());
+ else replacement = JavacResolution.typeToJCTree(componentType, localNode.getTreeMaker(), localNode.getAst());
+ } else {
+ replacement = JavacResolution.typeToJCTree(type, localNode.getTreeMaker(), localNode.getAst());
}
- replacement = JavacResolution.typeToJCTree(type, localNode.getTreeMaker(), localNode.getAst());
+
if (replacement != null) {
local.vartype = replacement;
localNode.getAst().setChanged();
}
- else local.vartype = oldVarType;
+ else local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());;
} catch (JavacResolution.TypeNotConvertibleException e) {
localNode.addError("Cannot use 'val' here because initializer expression does not have a representable type: " + e.getMessage());
- local.vartype = oldVarType;
+ local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());;
}
} catch (RuntimeException e) {
- local.vartype = oldVarType;
+ local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());;
throw e;
}
}
- // TODO search for val decls in either kind of for.
}
}