From 4dbe3802fda3b317bb82bca80d7c69f58b239cfd Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 28 Jul 2013 03:10:34 +0200 Subject: more progress. This one is less JDK8 compatible, but it has major refactorings to make JDK6-8 support possibly with much prettier code. --- src/utils/lombok/javac/Javac.java | 86 ++------------ src/utils/lombok/javac/JavacTreeMaker.java | 178 +++++++++++++++++++++++----- src/utils/lombok/javac/TreeMirrorMaker.java | 5 +- 3 files changed, 158 insertions(+), 111 deletions(-) (limited to 'src/utils/lombok') diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index b0540997..014007d4 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -47,7 +47,6 @@ import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCLiteral; -import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** @@ -133,34 +132,17 @@ public class Javac { public static final TypeTag CTC_CLASS = typeTag("CLASS"); public static final TreeTag CTC_NOT_EQUAL = treeTag("NE"); + public static final TreeTag CTC_POS = treeTag("POS"); + public static final TreeTag CTC_NEG = treeTag("NEG"); public static final TreeTag CTC_NOT = treeTag("NOT"); + public static final TreeTag CTC_COMPL = treeTag("COMPL"); public static final TreeTag CTC_BITXOR = treeTag("BITXOR"); public static final TreeTag CTC_UNSIGNED_SHIFT_RIGHT = treeTag("USR"); public static final TreeTag CTC_MUL = treeTag("MUL"); public static final TreeTag CTC_PLUS = treeTag("PLUS"); public static final TreeTag CTC_EQUAL = treeTag("EQ"); - - public static boolean compareCTC(TreeTag ctc1, TreeTag ctc2) { - boolean ctc1IsNull = ctc1 == null || ctc1.value == null; - boolean ctc2IsNull = ctc2 == null || ctc2.value == null; - if (ctc1IsNull || ctc2IsNull) return ctc1IsNull && ctc2IsNull; - return ctc1.value.equals(ctc2.value); - } - - public static boolean compareCTC(TypeTag ctc1, TypeTag ctc2) { - boolean ctc1IsNull = ctc1 == null || ctc1.value == null; - boolean ctc2IsNull = ctc2 == null || ctc2.value == null; - if (ctc1IsNull || ctc2IsNull) return ctc1IsNull && ctc2IsNull; - return ctc1.value.equals(ctc2.value); - } - - public static Object getTreeTypeTag(JCPrimitiveTypeTree tree) { - return tree.typetag; - } - - public static Object getTreeTypeTag(JCLiteral tree) { - return tree.typetag; - } + public static final TreeTag CTC_PREINC = treeTag("PREINC"); + public static final TreeTag CTC_PREDEC = treeTag("PREDEC"); private static final Method getExtendsClause, getEndPosition; @@ -245,7 +227,7 @@ public class Javac { return new JCNoType(((Integer) tag.value).intValue()); } else { try { - if (compareCTC(tag, CTC_VOID)) { + if (CTC_VOID.equals(tag)) { return (Type) JC_VOID_TYPE.newInstance(); } else { return (Type) JC_NO_TYPE.newInstance(); @@ -276,28 +258,9 @@ public class Javac { } } - private static final Field JCTREE_TAG, JCLITERAL_TYPETAG, JCPRIMITIVETYPETREE_TYPETAG, JCCOMPILATIONUNIT_ENDPOSITIONS, JCCOMPILATIONUNIT_DOCCOMMENTS; - private static final Method JCTREE_GETTAG; + private static final Field JCCOMPILATIONUNIT_ENDPOSITIONS, JCCOMPILATIONUNIT_DOCCOMMENTS; static { Field f = null; - try { - f = JCTree.class.getDeclaredField("tag"); - } catch (NoSuchFieldException e) {} - JCTREE_TAG = f; - - f = null; - try { - f = JCLiteral.class.getDeclaredField("typetag"); - } catch (NoSuchFieldException e) {} - JCLITERAL_TYPETAG = f; - - f = null; - try { - f = JCPrimitiveTypeTree.class.getDeclaredField("typetag"); - } catch (NoSuchFieldException e) {} - JCPRIMITIVETYPETREE_TYPETAG = f; - - f = null; try { f = JCCompilationUnit.class.getDeclaredField("endPositions"); } catch (NoSuchFieldException e) {} @@ -308,41 +271,6 @@ public class Javac { f = JCCompilationUnit.class.getDeclaredField("docComments"); } catch (NoSuchFieldException e) {} JCCOMPILATIONUNIT_DOCCOMMENTS = f; - - Method m = null; - try { - m = JCTree.class.getDeclaredMethod("getTag"); - } catch (NoSuchMethodException e) {} - JCTREE_GETTAG = m; - } - - public static Object getTag(JCTree node) { - if (JCTREE_GETTAG != null) { - try { - return JCTREE_GETTAG.invoke(node); - } catch (Exception e) {} - } - try { - return JCTREE_TAG.get(node); - } catch (Exception e) { - throw new IllegalStateException("Can't get node tag"); - } - } - - public static Object getTypeTag(JCLiteral node) { - try { - return JCLITERAL_TYPETAG.get(node); - } catch (Exception e) { - throw new IllegalStateException("Can't get JCLiteral typetag"); - } - } - - public static Object getTypeTag(JCPrimitiveTypeTree node) { - try { - return JCPRIMITIVETYPETREE_TYPETAG.get(node); - } catch (Exception e) { - throw new IllegalStateException("Can't get JCPrimitiveTypeTree typetag"); - } } static RuntimeException sneakyThrow(Throwable t) { diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java index 916c8735..edbf55af 100644 --- a/src/utils/lombok/javac/JavacTreeMaker.java +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -21,6 +21,7 @@ */ package lombok.javac; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; @@ -29,6 +30,7 @@ import java.util.concurrent.ConcurrentMap; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayAccess; @@ -81,6 +83,7 @@ import com.sun.tools.javac.tree.JCTree.JCWhileLoop; import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.tree.JCTree.LetExpr; import com.sun.tools.javac.tree.JCTree.TypeBoundKind; +import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; @@ -92,49 +95,101 @@ public class JavacTreeMaker { this.tm = tm; } + public TreeMaker getUnderlyingTreeMaker() { + return tm; + } + public JavacTreeMaker at(int pos) { tm.at(pos); return this; } private static class MethodId { + private final Class owner; private final String name; private final Class returnType; private final Class[] paramTypes; - MethodId(String name, Class returnType, Class... types) { + MethodId(Class owner, String name, Class returnType, Class... types) { + this.owner = owner; this.name = name; this.paramTypes = types; this.returnType = returnType; } - } - private static Object getFieldCached(ConcurrentMap cache, String className, String fieldName) { - Object value = cache.get(fieldName); - if (value != null) return value; - try { - value = Class.forName(className).getField(fieldName).get(null); - } catch (NoSuchFieldException e) { - throw Javac.sneakyThrow(e); - } catch (IllegalAccessException e) { - throw Javac.sneakyThrow(e); - } catch (ClassNotFoundException e) { - throw Javac.sneakyThrow(e); + private static class SchroedingerType { + final Object value; + + private SchroedingerType(Object value) { + this.value = value; + } + + @Override public int hashCode() { + return value == null ? -1 : value.hashCode(); } - cache.putIfAbsent(fieldName, value); - return value; + @Override public boolean equals(Object obj) { + if (obj instanceof SchroedingerType) { + Object other = ((SchroedingerType) obj).value; + return value == null ? other == null : value.equals(other); + } + return false; + } + + static Object getFieldCached(ConcurrentMap cache, String className, String fieldName) { + Object value = cache.get(fieldName); + if (value != null) return value; + try { + value = Class.forName(className).getField(fieldName).get(null); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } catch (ClassNotFoundException e) { + throw Javac.sneakyThrow(e); + } + + cache.putIfAbsent(fieldName, value); + return value; + } + + static Object getFieldCached(ConcurrentMap, Field> cache, Object ref, String fieldName) { + Class c = ref.getClass(); + Field field = cache.get(c); + if (field == null) { + try { + field = c.getField(fieldName); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } + field.setAccessible(true); + Field old = cache.putIfAbsent(c, field); + if (old != null) field = old; + } + + try { + return field.get(ref); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } } - private static interface SchroedingerType {} - - public static class TypeTag implements SchroedingerType { + public static class TypeTag extends SchroedingerType { private static final ConcurrentMap TYPE_TAG_CACHE = new ConcurrentHashMap(); - public final Object value; + private static final ConcurrentMap, Field> FIELD_CACHE = new ConcurrentHashMap, Field>(); private TypeTag(Object value) { - this.value = value; + super(value); + } + + public static TypeTag typeTag(JCTree o) { + return new TypeTag(getFieldCached(FIELD_CACHE, o, "typetag")); + } + + public static TypeTag typeTag(Type t) { + return new TypeTag(getFieldCached(FIELD_CACHE, t, "tag")); } public static TypeTag typeTag(String identifier) { @@ -142,17 +197,63 @@ public class JavacTreeMaker { } } - public static class TreeTag implements SchroedingerType { + public static class TreeTag extends SchroedingerType { private static final ConcurrentMap TREE_TAG_CACHE = new ConcurrentHashMap(); - public final Object value; + private static final Field TAG_FIELD; + private static final Method TAG_METHOD; + private static final MethodId OP_PREC = MethodId(TreeInfo.class, "opPrec", int.class, TreeTag.class); + + static { + Method m = null; + try { + m = JCTree.class.getDeclaredMethod("getTag"); + m.setAccessible(true); + } catch (NoSuchMethodException e) {} + + if (m != null) { + TAG_FIELD = null; + TAG_METHOD = m; + } else { + Field f = null; + try { + f = JCTree.class.getDeclaredField("tag"); + f.setAccessible(true); + } catch (NoSuchFieldException e) {} + TAG_FIELD = f; + TAG_METHOD = null; + } + } private TreeTag(Object value) { - this.value = value; + super(value); + } + + public static TreeTag treeTag(JCTree o) { + try { + if (TAG_METHOD != null) return new TreeTag(TAG_METHOD.invoke(o)); + else return new TreeTag(TAG_FIELD.get(o)); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } } public static TreeTag treeTag(String identifier) { return new TreeTag(getFieldCached(TREE_TAG_CACHE, Javac.getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.tree.JCTree" : "com.sun.tools.javac.tree.JCTree$Tag", identifier)); } + + public int getOperatorPrecedenceLevel() { + return invokeAny(null, OP_PREC, value); + } + + public boolean isPrefixUnaryOp() { + return Javac.CTC_NEG.equals(this) || Javac.CTC_POS.equals(this) || Javac.CTC_NOT.equals(this) || Javac.CTC_COMPL.equals(this) || Javac.CTC_PREDEC.equals(this) || Javac.CTC_PREINC.equals(this); + } + } + + static MethodId MethodId(Class owner, String name, Class returnType, Class... types) { + return new MethodId(owner, name, returnType, types); } /** @@ -163,8 +264,8 @@ public class JavacTreeMaker { * Either (A) the type listed here is the same as, or a subtype of, the type of the method in javac's TreeMaker, or * (B) the type listed here is a subtype of SchroedingerType. */ - static MethodId MethodId(String name, Class returnType, Class... types) { - return new MethodId(name, returnType, types); + static MethodId MethodId(String name, Class returnType, Class... types) { + return new MethodId(TreeMaker.class, name, returnType, types); } /** @@ -176,7 +277,7 @@ public class JavacTreeMaker { if (m.getName().equals(name)) { @SuppressWarnings("unchecked") Class r = (Class) m.getReturnType(); Class[] p = m.getParameterTypes(); - return new MethodId(name, r, p); + return new MethodId(TreeMaker.class, name, r, p); } } @@ -185,14 +286,27 @@ public class JavacTreeMaker { private static final ConcurrentHashMap, Method> METHOD_CACHE = new ConcurrentHashMap, Method>(); private J invoke(MethodId m, Object... args) { + return invokeAny(tm, m, args); + } + + @SuppressWarnings("unchecked") private static J invokeAny(Object owner, MethodId m, Object... args) { Method method = METHOD_CACHE.get(m); if (method == null) method = addToCache(m); try { - return m.returnType.cast(method.invoke(tm, args)); + if (m.returnType.isPrimitive()) { + Object res = method.invoke(owner, args); + String sn = res.getClass().getSimpleName().toLowerCase(); + if (!sn.startsWith(m.returnType.getSimpleName())) throw new ClassCastException(res.getClass() + " to " + m.returnType); + return (J) res; + } + return m.returnType.cast(method.invoke(owner, args)); } catch (InvocationTargetException e) { throw Javac.sneakyThrow(e.getCause()); } catch (IllegalAccessException e) { throw Javac.sneakyThrow(e); + } catch (IllegalArgumentException e) { + System.err.println(method); + throw Javac.sneakyThrow(e); } } @@ -200,7 +314,7 @@ public class JavacTreeMaker { Method found = null; outer: - for (Method method : TreeMaker.class.getDeclaredMethods()) { + for (Method method : m.owner.getDeclaredMethods()) { if (!m.name.equals(method.getName())) continue; Class[] t = method.getParameterTypes(); if (t.length != m.paramTypes.length) continue; @@ -210,7 +324,7 @@ public class JavacTreeMaker { if (t[i].isPrimitive()) { if (t[i] != m.paramTypes[i]) continue outer; } else { - if (t[i].isAssignableFrom(m.paramTypes[i])) continue outer; + if (!t[i].isAssignableFrom(m.paramTypes[i])) continue outer; } } } @@ -659,4 +773,10 @@ public class JavacTreeMaker { public JCStatement Call(JCExpression apply) { return invoke(Call, apply); } + + //javac versions: 6-8 + private static final MethodId Type = MethodId("Type"); + public JCExpression Type(Type type) { + return invoke(Type, type); + } } \ No newline at end of file diff --git a/src/utils/lombok/javac/TreeMirrorMaker.java b/src/utils/lombok/javac/TreeMirrorMaker.java index 30915572..23ec2406 100644 --- a/src/utils/lombok/javac/TreeMirrorMaker.java +++ b/src/utils/lombok/javac/TreeMirrorMaker.java @@ -31,7 +31,6 @@ import com.sun.source.tree.VariableTree; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeCopier; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; /** @@ -47,8 +46,8 @@ import com.sun.tools.javac.util.List; public class TreeMirrorMaker extends TreeCopier { private final IdentityHashMap originalToCopy = new IdentityHashMap(); - public TreeMirrorMaker(TreeMaker maker) { - super(maker); + public TreeMirrorMaker(JavacTreeMaker maker) { + super(maker.getUnderlyingTreeMaker()); } @Override public T copy(T original) { -- cgit