From 12771880260d57209afcda15fd2b00f3181c38a6 Mon Sep 17 00:00:00 2001 From: Robbert Jan Grootjans Date: Fri, 8 Mar 2013 16:52:14 +0100 Subject: Added switch to CommentsCatcher. Assumption, until proven otherwise is that JDK8 behaves similar to JDK7. --- src/utils/lombok/javac/CommentCatcher.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index 474dc43d..e3754627 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -64,8 +64,10 @@ public class CommentCatcher { try { if (JavaCompiler.version().startsWith("1.6")) { Class.forName("lombok.javac.java6.CommentCollectingScannerFactory").getMethod("preRegister", Context.class).invoke(null, context); - } else { + } else if (JavaCompiler.version().startsWith("1.7") || JavaCompiler.version().startsWith("1.8")) { Class.forName("lombok.javac.java7.CommentCollectingScannerFactory").getMethod("preRegister", Context.class).invoke(null, context); + } else { + throw new IllegalStateException("No comments parser for compiler version " + JavaCompiler.version()); } } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException)e; @@ -79,10 +81,13 @@ public class CommentCatcher { if (JavaCompiler.version().startsWith("1.6")) { Class parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory"); parserFactory.getMethod("setInCompiler",JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); - } else { + } else if (JavaCompiler.version().startsWith("1.7") || JavaCompiler.version().startsWith("1.8")) { Class parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory"); parserFactory.getMethod("setInCompiler",JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + } else { + throw new IllegalStateException("No comments parser for compiler version " + JavaCompiler.version()); } + } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException)e; throw new RuntimeException(e); -- cgit From 0b100f22071236907142e4c0fb85ffa50102818d Mon Sep 17 00:00:00 2001 From: Robbert Jan Grootjans Date: Fri, 22 Mar 2013 18:23:44 +0100 Subject: Refactored out references to TypeTags. Instead they are retrieved dynamically, with a pinch of caching during runtime. We already had some fixes to make sure that compile time constanst were not inlined, but we need to take into account that a lot of the Integer-based enums have been replaced with actual enums. Also, certain TreeMaker methods needed to be invoked dynamically with reflection. This needs to be reviewed, and if it turns out that these changes are too dramatic, we should fork out a larger part of our code for specific JVM versions. --- src/utils/lombok/javac/Javac.java | 237 ++++++++++++++++++++++++++++++++------ 1 file changed, 202 insertions(+), 35 deletions(-) (limited to 'src/utils') diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index 75bb2dbf..cbbd6730 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -21,29 +21,33 @@ */ package lombok.javac; +import java.lang.reflect.Method; import java.util.regex.Pattern; -import com.sun.tools.javac.code.TypeTags; +import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCBinary; 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.JCUnary; +import com.sun.tools.javac.tree.TreeMaker; /** * Container for static utility methods relevant to lombok's operation on javac. */ public class Javac { private Javac() { - //prevent instantiation + // prevent instantiation } /** Matches any of the 8 primitive names, such as {@code boolean}. */ - private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile( - "^(boolean|byte|short|int|long|float|double|char)$"); + private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$"); /** - * Checks if the given expression (that really ought to refer to a type expression) represents a primitive type. + * Checks if the given expression (that really ought to refer to a type + * expression) represents a primitive type. */ public static boolean isPrimitive(JCExpression ref) { String typeName = ref.toString(); @@ -51,15 +55,16 @@ public class Javac { } /** - * Turns an expression into a guessed intended literal. Only works for literals, as you can imagine. + * Turns an expression into a guessed intended literal. Only works for + * literals, as you can imagine. * * Will for example turn a TrueLiteral into 'Boolean.valueOf(true)'. */ public static Object calculateGuess(JCExpression expr) { if (expr instanceof JCLiteral) { - JCLiteral lit = (JCLiteral)expr; + JCLiteral lit = (JCLiteral) expr; if (lit.getKind() == com.sun.source.tree.Tree.Kind.BOOLEAN_LITERAL) { - return ((Number)lit.value).intValue() == 0 ? false : true; + return ((Number) lit.value).intValue() == 0 ? false : true; } return lit.value; } else if (expr instanceof JCIdent || expr instanceof JCFieldAccess) { @@ -70,45 +75,207 @@ public class Javac { if (idx > -1) x = x.substring(idx + 1); } return x; - } else return null; + } else + return null; } - public static final int CTC_BOOLEAN = getCtcInt(TypeTags.class, "BOOLEAN"); - public static final int CTC_INT = getCtcInt(TypeTags.class, "INT"); - public static final int CTC_DOUBLE = getCtcInt(TypeTags.class, "DOUBLE"); - public static final int CTC_FLOAT = getCtcInt(TypeTags.class, "FLOAT"); - public static final int CTC_SHORT = getCtcInt(TypeTags.class, "SHORT"); - public static final int CTC_BYTE = getCtcInt(TypeTags.class, "BYTE"); - public static final int CTC_LONG = getCtcInt(TypeTags.class, "LONG"); - public static final int CTC_CHAR = getCtcInt(TypeTags.class, "CHAR"); - public static final int CTC_VOID = getCtcInt(TypeTags.class, "VOID"); - public static final int CTC_NONE = getCtcInt(TypeTags.class, "NONE"); - - public static final int CTC_NOT_EQUAL = getCtcInt(JCTree.class, "NE"); - public static final int CTC_NOT = getCtcInt(JCTree.class, "NOT"); - public static final int CTC_BITXOR = getCtcInt(JCTree.class, "BITXOR"); - public static final int CTC_UNSIGNED_SHIFT_RIGHT = getCtcInt(JCTree.class, "USR"); - public static final int CTC_MUL = getCtcInt(JCTree.class, "MUL"); - public static final int CTC_PLUS = getCtcInt(JCTree.class, "PLUS"); - public static final int CTC_BOT = getCtcInt(TypeTags.class, "BOT"); - public static final int CTC_EQUAL = getCtcInt(JCTree.class, "EQ"); + public static final Object CTC_BOOLEAN = getTypeTag("BOOLEAN"); + public static final Object CTC_INT = getTypeTag("INT"); + public static final Object CTC_DOUBLE = getTypeTag("DOUBLE"); + public static final Object CTC_FLOAT = getTypeTag("FLOAT"); + public static final Object CTC_SHORT = getTypeTag("SHORT"); + public static final Object CTC_BYTE = getTypeTag("BYTE"); + public static final Object CTC_LONG = getTypeTag("LONG"); + public static final Object CTC_CHAR = getTypeTag("CHAR"); + public static final Object CTC_VOID = getTypeTag("VOID"); + public static final Object CTC_NONE = getTypeTag("NONE"); + public static final Object CTC_BOT = getTypeTag("BOT"); + public static final Object CTC_CLASS = getTypeTag("CLASS"); + + public static final Object CTC_NOT_EQUAL = getTreeTag("NE"); + public static final Object CTC_NOT = getTreeTag("NOT"); + public static final Object CTC_BITXOR = getTreeTag("BITXOR"); + public static final Object CTC_UNSIGNED_SHIFT_RIGHT = getTreeTag("USR"); + public static final Object CTC_MUL = getTreeTag("MUL"); + public static final Object CTC_PLUS = getTreeTag("PLUS"); + public static final Object CTC_EQUAL = getTreeTag("EQ"); + +// /** +// * Retrieves the current ordinal position of a type tag. +// * +// * For JDK 8 this is the ordinal position within the +// * com.sun.tools.javac.code.TypeTag enum for JDK 7 and lower, +// * this is the value of the constant within +// * com.sun.tools.javac.code.TypeTags +// * +// * Solves the problem of compile time constant inlining, resulting in lombok +// * having the wrong value (javac compiler changes private api constants from +// * time to time). +// * +// * @param identifier +// * @return the ordinal value of the typetag constant +// */ +// public static int getTypeTag(String identifier) { +// try { +// if (JavaCompiler.version().startsWith("1.8")) { +// Object enumInstance = Class.forName("com.sun.tools.javac.code.TypeTag").getField(identifier).get(null); +// return (int) Class.forName("com.sun.tools.javac.code.TypeTag").getField("order").get(enumInstance); +// +// } else { +// return (int) Class.forName("com.sun.tools.javac.code.TypeTags").getField(identifier).get(null); +// } +// } catch (NoSuchFieldException e) { +// throw new RuntimeException(e); +// } catch (IllegalAccessException e) { +// throw new RuntimeException(e); +// } catch (Exception e) { +// if (e instanceof RuntimeException) throw (RuntimeException) e; +// throw new RuntimeException(e); +// } +// } + + + + public static boolean compareCTC(Object ctc1, Object ctc2) { + return ctc1.equals(ctc2); + } /** - * Retrieves a compile time constant of type int from the specified class location. + * Retrieves the current type tag. The actual type object differs depending on the Compiler version + * + * For JDK 8 this is an enum value of type com.sun.tools.javac.code.TypeTag + * for JDK 7 and lower, this is the value of the constant within com.sun.tools.javac.code.TypeTags * - * Solves the problem of compile time constant inlining, resulting in lombok having the wrong value - * (javac compiler changes private api constants from time to time) + * Solves the problem of compile time constant inlining, resulting in lombok + * having the wrong value (javac compiler changes private api constants from + * time to time). * - * @param ctcLocation location of the compile time constant - * @param identifier the name of the field of the compile time constant. + * @param identifier + * @return the ordinal value of the typetag constant */ - public static int getCtcInt(Class ctcLocation, String identifier) { + public static Object getTypeTag(String identifier) { try { - return (Integer)ctcLocation.getField(identifier).get(null); + if (JavaCompiler.version().startsWith("1.8")) { + return Class.forName("com.sun.tools.javac.code.TypeTag").getField(identifier).get(null); + } else { + return Class.forName("com.sun.tools.javac.code.TypeTags").getField(identifier).get(null); + } } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); + } catch (Exception e) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + throw new RuntimeException(e); + } + } + + public static Object getTreeTag(String identifier) { + try { + if (JavaCompiler.version().startsWith("1.8")) { + return Class.forName("com.sun.tools.javac.tree.JCTree$Tag").getField(identifier).get(null); + } else { + return Class.forName("com.sun.tools.javac.tree.JCTree").getField(identifier).get(null); + } + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (Exception e) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + throw new RuntimeException(e); } } + + + public static Object getTreeTypeTag(JCTree tree) { + try { + return TreeMaker.class.getField("typetag").get(tree); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (Exception e) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + throw new RuntimeException(e); + } + } + + public static JCExpression makeTypeIdent(TreeMaker maker, Object ctc) { + try { + Method createIdent; + if (JavaCompiler.version().startsWith("1.8")) { + createIdent = TreeMaker.class.getMethod("TypeIdent", Class.forName("com.sun.tools.javac.code.TypeTag")); + } else { + createIdent = TreeMaker.class.getMethod("TypeIdent", Integer.TYPE); + } + return (JCExpression) createIdent.invoke(maker, ctc); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (Exception e) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + throw new RuntimeException(e); + } + } + + public static JCLiteral makeLiteral(TreeMaker maker, Object ctc, Object argument) { + try { + Method createLiteral; + if (JavaCompiler.version().startsWith("1.8")) { + createLiteral = TreeMaker.class.getMethod("Literal", Class.forName("com.sun.tools.javac.code.TypeTag"), Object.class); + } else { + createLiteral = TreeMaker.class.getMethod("Literal", Integer.TYPE, Object.class); + } + return (JCLiteral) createLiteral.invoke(maker, ctc, argument); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (Exception e) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + throw new RuntimeException(e); + } + } + + public static JCUnary makeUnary(TreeMaker maker, Object ctc, JCExpression argument) { + try { + Method createUnary; + if (JavaCompiler.version().startsWith("1.8")) { + createUnary = TreeMaker.class.getMethod("Unary", Class.forName("com.sun.tools.javac.code.TypeTag"), JCExpression.class); + } else { + createUnary = TreeMaker.class.getMethod("Unary", Integer.TYPE, JCExpression.class); + } + return (JCUnary) createUnary.invoke(maker, ctc, argument); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (Exception e) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + throw new RuntimeException(e); + } + } + + public static JCBinary makeBinary(TreeMaker maker, Object ctc, JCExpression rhsArgument, JCExpression lhsArgument) { + try { + Method createUnary; + if (JavaCompiler.version().startsWith("1.8")) { + createUnary = TreeMaker.class.getMethod("Binary", Class.forName("com.sun.tools.javac.code.TypeTag"), JCExpression.class, JCExpression.class); + } else { + createUnary = TreeMaker.class.getMethod("Binary", Integer.TYPE, JCExpression.class, JCExpression.class); + } + return (JCBinary) createUnary.invoke(maker, ctc, rhsArgument, lhsArgument); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (Exception e) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + throw new RuntimeException(e); + } + } + + } -- cgit From 172202add2d0cb63e5b0780e7e3fc6000e43a3d9 Mon Sep 17 00:00:00 2001 From: Robbert Jan Grootjans Date: Fri, 5 Apr 2013 14:37:11 +0200 Subject: Some small fixes for Java 7 --- src/utils/lombok/javac/Javac.java | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/utils') diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index cbbd6730..b766630f 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -22,6 +22,7 @@ package lombok.javac; import java.lang.reflect.Method; +import java.util.Objects; import java.util.regex.Pattern; import com.sun.tools.javac.main.JavaCompiler; @@ -31,6 +32,7 @@ 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.tree.JCTree.JCUnary; import com.sun.tools.javac.tree.TreeMaker; @@ -137,7 +139,7 @@ public class Javac { public static boolean compareCTC(Object ctc1, Object ctc2) { - return ctc1.equals(ctc2); + return Objects.equals(ctc1, ctc2); } /** @@ -187,20 +189,14 @@ public class Javac { } } - - public static Object getTreeTypeTag(JCTree tree) { - try { - return TreeMaker.class.getField("typetag").get(tree); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException) e; - throw new RuntimeException(e); - } + public static Object getTreeTypeTag(JCPrimitiveTypeTree tree) { + return tree.typetag; } + public static Object getTreeTypeTag(JCLiteral tree) { + return tree.typetag; + } + public static JCExpression makeTypeIdent(TreeMaker maker, Object ctc) { try { Method createIdent; -- cgit From 4c03e3d220900431085897878d4888bf530b31ec Mon Sep 17 00:00:00 2001 From: Robbert Jan Grootjans Date: Fri, 5 Apr 2013 17:28:44 +0200 Subject: Type fixes for JDK7 --- src/utils/lombok/javac/JCNoTypeFactory.java | 11 +++++++++ src/utils/lombok/javac/Javac.java | 37 ----------------------------- 2 files changed, 11 insertions(+), 37 deletions(-) create mode 100644 src/utils/lombok/javac/JCNoTypeFactory.java (limited to 'src/utils') diff --git a/src/utils/lombok/javac/JCNoTypeFactory.java b/src/utils/lombok/javac/JCNoTypeFactory.java new file mode 100644 index 00000000..e7be7665 --- /dev/null +++ b/src/utils/lombok/javac/JCNoTypeFactory.java @@ -0,0 +1,11 @@ +package lombok.javac; + +import com.sun.tools.javac.code.Symbol.TypeSymbol; +import com.sun.tools.javac.code.Type; + + +public class JCNoTypeFactory { + public static final Type getJCNotType(Object typeTag, TypeSymbol tsym) { + + } +} diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index b766630f..9f2936a8 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -26,7 +26,6 @@ import java.util.Objects; import java.util.regex.Pattern; import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCBinary; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; @@ -102,42 +101,6 @@ public class Javac { public static final Object CTC_PLUS = getTreeTag("PLUS"); public static final Object CTC_EQUAL = getTreeTag("EQ"); -// /** -// * Retrieves the current ordinal position of a type tag. -// * -// * For JDK 8 this is the ordinal position within the -// * com.sun.tools.javac.code.TypeTag enum for JDK 7 and lower, -// * this is the value of the constant within -// * com.sun.tools.javac.code.TypeTags -// * -// * Solves the problem of compile time constant inlining, resulting in lombok -// * having the wrong value (javac compiler changes private api constants from -// * time to time). -// * -// * @param identifier -// * @return the ordinal value of the typetag constant -// */ -// public static int getTypeTag(String identifier) { -// try { -// if (JavaCompiler.version().startsWith("1.8")) { -// Object enumInstance = Class.forName("com.sun.tools.javac.code.TypeTag").getField(identifier).get(null); -// return (int) Class.forName("com.sun.tools.javac.code.TypeTag").getField("order").get(enumInstance); -// -// } else { -// return (int) Class.forName("com.sun.tools.javac.code.TypeTags").getField(identifier).get(null); -// } -// } catch (NoSuchFieldException e) { -// throw new RuntimeException(e); -// } catch (IllegalAccessException e) { -// throw new RuntimeException(e); -// } catch (Exception e) { -// if (e instanceof RuntimeException) throw (RuntimeException) e; -// throw new RuntimeException(e); -// } -// } - - - public static boolean compareCTC(Object ctc1, Object ctc2) { return Objects.equals(ctc1, ctc2); } -- cgit From 1b4d8669c48af215c38a73f6dfd15741619a1c45 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 23 Jul 2013 00:54:59 +0200 Subject: A source file with just @Getter in it now compiles in javac8, but there is still a looooong way to go. --- src/utils/lombok/javac/CommentCatcher.java | 10 +-- src/utils/lombok/javac/Javac.java | 126 ++++++++++++++++++++++------- 2 files changed, 101 insertions(+), 35 deletions(-) (limited to 'src/utils') diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index 8d1e71c0..eb747554 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -25,8 +25,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.WeakHashMap; -import lombok.Lombok; - import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; @@ -73,9 +71,9 @@ public class CommentCatcher { } scannerFactory.getMethod("preRegister", Context.class).invoke(null, context); } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); + throw Javac.sneakyThrow(e.getCause()); } catch (Exception e) { - throw Lombok.sneakyThrow(e); + throw Javac.sneakyThrow(e); } } @@ -89,9 +87,9 @@ public class CommentCatcher { } parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); + throw Javac.sneakyThrow(e.getCause()); } catch (Exception e) { - throw Lombok.sneakyThrow(e); + throw Javac.sneakyThrow(e); } } } diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index dfa51e00..1f2a7031 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -35,22 +35,23 @@ import javax.lang.model.type.NoType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeVisitor; -import lombok.Lombok; - import com.sun.tools.javac.code.Type; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCBinary; import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 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.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; +import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCUnary; import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; @@ -62,6 +63,9 @@ public class Javac { // prevent instantiation } + private static final ConcurrentMap TYPE_TAG_CACHE = new ConcurrentHashMap(); + private static final ConcurrentMap TREE_TAG_CACHE = new ConcurrentHashMap(); + /** Matches any of the 8 primitive names, such as {@code boolean}. */ private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$"); @@ -148,10 +152,6 @@ public class Javac { return ctc1 == null ? ctc2 == null : ctc1.equals(ctc2); } - private static final ConcurrentMap TYPE_TAG_CACHE = new ConcurrentHashMap(); - private static final ConcurrentMap TREE_TAG_CACHE = new ConcurrentHashMap(); - - /** * Retrieves the provided TypeTag value, in a compiler version independent manner. * @@ -168,7 +168,7 @@ public class Javac { * @return the value of the typetag constant (either enum instance or an Integer object). */ public static Object getTypeTag(String identifier) { - return getFieldCached(TYPE_TAG_CACHE, getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTag" : "com.sun.tools.javac.code.TypeTags", identifier); + return getFieldCached(TYPE_TAG_CACHE, getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTags" : "com.sun.tools.javac.code.TypeTag", identifier); } public static Object getTreeTag(String identifier) { @@ -181,11 +181,11 @@ public class Javac { try { value = Class.forName(className).getField(fieldName).get(null); } catch (NoSuchFieldException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } catch (ClassNotFoundException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } cache.putIfAbsent(fieldName, value); @@ -200,8 +200,8 @@ public class Javac { return tree.typetag; } - private static final Method createIdent, createLiteral, createUnary, createBinary; - + private static final Method createIdent, createLiteral, createUnary, createBinary, createThrow, getExtendsClause, getEndPosition; + static { if (getJavaCompilerVersion() < 8) { createIdent = getMethod(TreeMaker.class, "TypeIdent", int.class); @@ -220,23 +220,40 @@ public class Javac { if (getJavaCompilerVersion() < 8) { createUnary = getMethod(TreeMaker.class, "Unary", int.class, JCExpression.class); } else { - createUnary = getMethod(TreeMaker.class, "Unary", "com.sun.tools.javac.code.TypeTag", JCExpression.class.getName()); + createUnary = getMethod(TreeMaker.class, "Unary", "com.sun.tools.javac.tree.JCTree$Tag", JCExpression.class.getName()); } createUnary.setAccessible(true); if (getJavaCompilerVersion() < 8) { createBinary = getMethod(TreeMaker.class, "Binary", Integer.TYPE, JCExpression.class, JCExpression.class); } else { - createBinary = getMethod(TreeMaker.class, "Binary", "com.sun.tools.javac.code.TypeTag", JCExpression.class.getName(), JCExpression.class.getName()); + createBinary = getMethod(TreeMaker.class, "Binary", "com.sun.tools.javac.tree.JCTree$Tag", JCExpression.class.getName(), JCExpression.class.getName()); + } + createBinary.setAccessible(true); + + if (getJavaCompilerVersion() < 8) { + createThrow = getMethod(TreeMaker.class, "Throw", JCTree.class); + } else { + createThrow = getMethod(TreeMaker.class, "Throw", JCExpression.class); } createBinary.setAccessible(true); + + getExtendsClause = getMethod(JCClassDecl.class, "getExtendsClause", new Class[0]); + getExtendsClause.setAccessible(true); + + if (getJavaCompilerVersion() < 8) { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", java.util.Map.class); + } else { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", "com.sun.tools.javac.tree.EndPosTable"); + } + getEndPosition.setAccessible(true); } private static Method getMethod(Class clazz, String name, Class... paramTypes) { try { return clazz.getMethod(name, paramTypes); } catch (NoSuchMethodException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } } @@ -246,9 +263,9 @@ public class Javac { for (int i = 0; i < paramTypes.length; i++) c[i] = Class.forName(paramTypes[i]); return clazz.getMethod(name, c); } catch (NoSuchMethodException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } catch (ClassNotFoundException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } } @@ -256,9 +273,9 @@ public class Javac { try { return (JCExpression) createIdent.invoke(maker, ctc); } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); + throw sneakyThrow(e.getCause()); } } @@ -266,9 +283,9 @@ public class Javac { try { return (JCLiteral) createLiteral.invoke(maker, ctc, argument); } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); + throw sneakyThrow(e.getCause()); } } @@ -276,9 +293,9 @@ public class Javac { try { return (JCUnary) createUnary.invoke(maker, ctc, argument); } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); + throw sneakyThrow(e.getCause()); } } @@ -286,9 +303,48 @@ public class Javac { try { return (JCBinary) createBinary.invoke(maker, ctc, lhsArgument, rhsArgument); } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } + } + + public static JCStatement makeThrow(TreeMaker maker, JCExpression expression) { + try { + return (JCStatement) createThrow.invoke(maker, expression); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); + throw sneakyThrow(e.getCause()); + } + } + + public static JCTree getExtendsClause(JCClassDecl decl) { + try { + return (JCTree) getExtendsClause.invoke(decl); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } + } + + public static Object getDocComments(JCCompilationUnit cu) { + try { + return JCCOMPILATIONUNIT_DOCCOMMENTS.get(cu); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } + } + + public static int getEndPosition(DiagnosticPosition pos, JCCompilationUnit top) { + try { + Object endPositions = JCCOMPILATIONUNIT_ENDPOSITIONS.get(top); + return (Integer) getEndPosition.invoke(pos, endPositions); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); } } @@ -318,9 +374,9 @@ public class Javac { return (Type) JC_NO_TYPE.newInstance(); } } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } catch (InstantiationException e) { - throw Lombok.sneakyThrow(e); + throw sneakyThrow(e); } } } @@ -343,7 +399,7 @@ public class Javac { } } - private static final Field JCTREE_TAG, JCLITERAL_TYPETAG, JCPRIMITIVETYPETREE_TYPETAG; + private static final Field JCTREE_TAG, JCLITERAL_TYPETAG, JCPRIMITIVETYPETREE_TYPETAG, JCCOMPILATIONUNIT_ENDPOSITIONS, JCCOMPILATIONUNIT_DOCCOMMENTS; private static final Method JCTREE_GETTAG; static { Field f = null; @@ -364,6 +420,18 @@ public class Javac { } catch (NoSuchFieldException e) {} JCPRIMITIVETYPETREE_TYPETAG = f; + f = null; + try { + f = JCCompilationUnit.class.getDeclaredField("endPositions"); + } catch (NoSuchFieldException e) {} + JCCOMPILATIONUNIT_ENDPOSITIONS = f; + + f = null; + try { + f = JCCompilationUnit.class.getDeclaredField("docComments"); + } catch (NoSuchFieldException e) {} + JCCOMPILATIONUNIT_DOCCOMMENTS = f; + Method m = null; try { m = JCTree.class.getDeclaredMethod("getTag"); @@ -424,7 +492,7 @@ public class Javac { } } - private static RuntimeException sneakyThrow(Throwable t) { + static RuntimeException sneakyThrow(Throwable t) { if (t == null) throw new NullPointerException("t"); Javac.sneakyThrow0(t); return null; -- cgit From e2af5ed0c7786e01bec861f21f2e5ec3bc5ea33f Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Fri, 26 Jul 2013 07:15:07 +0200 Subject: experiment: Can we wrap TreeMaker and remove a heck of a lot of opportunity to program handlers that are not cross javac6-8 compatible? --- src/utils/lombok/javac/Javac.java | 231 ++-------- src/utils/lombok/javac/JavacTreeMaker.java | 662 +++++++++++++++++++++++++++++ 2 files changed, 704 insertions(+), 189 deletions(-) create mode 100644 src/utils/lombok/javac/JavacTreeMaker.java (limited to 'src/utils') diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index 1f2a7031..b0540997 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -21,12 +21,12 @@ */ package lombok.javac; +import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; +import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; + import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,25 +35,20 @@ import javax.lang.model.type.NoType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeVisitor; +import lombok.javac.JavacTreeMaker.TreeTag; +import lombok.javac.JavacTreeMaker.TypeTag; + import com.sun.tools.javac.code.Type; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCBinary; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 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.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; -import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.tree.JCTree.JCTypeParameter; -import com.sun.tools.javac.tree.JCTree.JCUnary; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Name; /** * Container for static utility methods relevant to lombok's operation on javac. @@ -63,9 +58,6 @@ public class Javac { // prevent instantiation } - private static final ConcurrentMap TYPE_TAG_CACHE = new ConcurrentHashMap(); - private static final ConcurrentMap TREE_TAG_CACHE = new ConcurrentHashMap(); - /** Matches any of the 8 primitive names, such as {@code boolean}. */ private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$"); @@ -127,69 +119,39 @@ public class Javac { return null; } - public static final Object CTC_BOOLEAN = getTypeTag("BOOLEAN"); - public static final Object CTC_INT = getTypeTag("INT"); - public static final Object CTC_DOUBLE = getTypeTag("DOUBLE"); - public static final Object CTC_FLOAT = getTypeTag("FLOAT"); - public static final Object CTC_SHORT = getTypeTag("SHORT"); - public static final Object CTC_BYTE = getTypeTag("BYTE"); - public static final Object CTC_LONG = getTypeTag("LONG"); - public static final Object CTC_CHAR = getTypeTag("CHAR"); - public static final Object CTC_VOID = getTypeTag("VOID"); - public static final Object CTC_NONE = getTypeTag("NONE"); - public static final Object CTC_BOT = getTypeTag("BOT"); - public static final Object CTC_CLASS = getTypeTag("CLASS"); - - public static final Object CTC_NOT_EQUAL = getTreeTag("NE"); - public static final Object CTC_NOT = getTreeTag("NOT"); - public static final Object CTC_BITXOR = getTreeTag("BITXOR"); - public static final Object CTC_UNSIGNED_SHIFT_RIGHT = getTreeTag("USR"); - public static final Object CTC_MUL = getTreeTag("MUL"); - public static final Object CTC_PLUS = getTreeTag("PLUS"); - public static final Object CTC_EQUAL = getTreeTag("EQ"); - - public static boolean compareCTC(Object ctc1, Object ctc2) { - return ctc1 == null ? ctc2 == null : ctc1.equals(ctc2); - } - - /** - * Retrieves the provided TypeTag value, in a compiler version independent manner. - * - * The actual type object differs depending on the Compiler version: - *
    - *
  • For JDK 8 this is an enum value of type com.sun.tools.javac.code.TypeTag - *
  • for JDK 7 and lower, this is the value of the constant within com.sun.tools.javac.code.TypeTags - *
- * Solves the problem of compile time constant inlining, resulting in lombok - * having the wrong value (javac compiler changes private api constants from - * time to time). - * - * @param identifier Identifier to turn into a TypeTag. - * @return the value of the typetag constant (either enum instance or an Integer object). - */ - public static Object getTypeTag(String identifier) { - return getFieldCached(TYPE_TAG_CACHE, getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTags" : "com.sun.tools.javac.code.TypeTag", identifier); - } - - public static Object getTreeTag(String identifier) { - return getFieldCached(TREE_TAG_CACHE, getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.tree.JCTree" : "com.sun.tools.javac.tree.JCTree$Tag", identifier); + public static final TypeTag CTC_BOOLEAN = typeTag("BOOLEAN"); + public static final TypeTag CTC_INT = typeTag("INT"); + public static final TypeTag CTC_DOUBLE = typeTag("DOUBLE"); + public static final TypeTag CTC_FLOAT = typeTag("FLOAT"); + public static final TypeTag CTC_SHORT = typeTag("SHORT"); + public static final TypeTag CTC_BYTE = typeTag("BYTE"); + public static final TypeTag CTC_LONG = typeTag("LONG"); + public static final TypeTag CTC_CHAR = typeTag("CHAR"); + public static final TypeTag CTC_VOID = typeTag("VOID"); + public static final TypeTag CTC_NONE = typeTag("NONE"); + public static final TypeTag CTC_BOT = typeTag("BOT"); + public static final TypeTag CTC_CLASS = typeTag("CLASS"); + + public static final TreeTag CTC_NOT_EQUAL = treeTag("NE"); + public static final TreeTag CTC_NOT = treeTag("NOT"); + 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); } - 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 sneakyThrow(e); - } catch (IllegalAccessException e) { - throw sneakyThrow(e); - } catch (ClassNotFoundException e) { - throw sneakyThrow(e); - } - - cache.putIfAbsent(fieldName, value); - return 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) { @@ -200,44 +162,9 @@ public class Javac { return tree.typetag; } - private static final Method createIdent, createLiteral, createUnary, createBinary, createThrow, getExtendsClause, getEndPosition; + private static final Method getExtendsClause, getEndPosition; static { - if (getJavaCompilerVersion() < 8) { - createIdent = getMethod(TreeMaker.class, "TypeIdent", int.class); - } else { - createIdent = getMethod(TreeMaker.class, "TypeIdent", "com.sun.tools.javac.code.TypeTag"); - } - createIdent.setAccessible(true); - - if (getJavaCompilerVersion() < 8) { - createLiteral = getMethod(TreeMaker.class, "Literal", int.class, Object.class); - } else { - createLiteral = getMethod(TreeMaker.class, "Literal", "com.sun.tools.javac.code.TypeTag", "java.lang.Object"); - } - createLiteral.setAccessible(true); - - if (getJavaCompilerVersion() < 8) { - createUnary = getMethod(TreeMaker.class, "Unary", int.class, JCExpression.class); - } else { - createUnary = getMethod(TreeMaker.class, "Unary", "com.sun.tools.javac.tree.JCTree$Tag", JCExpression.class.getName()); - } - createUnary.setAccessible(true); - - if (getJavaCompilerVersion() < 8) { - createBinary = getMethod(TreeMaker.class, "Binary", Integer.TYPE, JCExpression.class, JCExpression.class); - } else { - createBinary = getMethod(TreeMaker.class, "Binary", "com.sun.tools.javac.tree.JCTree$Tag", JCExpression.class.getName(), JCExpression.class.getName()); - } - createBinary.setAccessible(true); - - if (getJavaCompilerVersion() < 8) { - createThrow = getMethod(TreeMaker.class, "Throw", JCTree.class); - } else { - createThrow = getMethod(TreeMaker.class, "Throw", JCExpression.class); - } - createBinary.setAccessible(true); - getExtendsClause = getMethod(JCClassDecl.class, "getExtendsClause", new Class[0]); getExtendsClause.setAccessible(true); @@ -269,56 +196,6 @@ public class Javac { } } - public static JCExpression makeTypeIdent(TreeMaker maker, Object ctc) { - try { - return (JCExpression) createIdent.invoke(maker, ctc); - } catch (IllegalAccessException e) { - throw sneakyThrow(e); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } - } - - public static JCLiteral makeLiteral(TreeMaker maker, Object ctc, Object argument) { - try { - return (JCLiteral) createLiteral.invoke(maker, ctc, argument); - } catch (IllegalAccessException e) { - throw sneakyThrow(e); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } - } - - public static JCUnary makeUnary(TreeMaker maker, Object ctc, JCExpression argument) { - try { - return (JCUnary) createUnary.invoke(maker, ctc, argument); - } catch (IllegalAccessException e) { - throw sneakyThrow(e); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } - } - - public static JCBinary makeBinary(TreeMaker maker, Object ctc, JCExpression lhsArgument, JCExpression rhsArgument) { - try { - return (JCBinary) createBinary.invoke(maker, ctc, lhsArgument, rhsArgument); - } catch (IllegalAccessException e) { - throw sneakyThrow(e); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } - } - - public static JCStatement makeThrow(TreeMaker maker, JCExpression expression) { - try { - return (JCStatement) createThrow.invoke(maker, expression); - } catch (IllegalAccessException e) { - throw sneakyThrow(e); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } - } - public static JCTree getExtendsClause(JCClassDecl decl) { try { return (JCTree) getExtendsClause.invoke(decl); @@ -363,9 +240,9 @@ public class Javac { JC_NO_TYPE = c; } - public static Type createVoidType(TreeMaker maker, Object tag) { + public static Type createVoidType(JavacTreeMaker maker, TypeTag tag) { if (Javac.getJavaCompilerVersion() < 8) { - return new JCNoType(((Integer) tag).intValue()); + return new JCNoType(((Integer) tag.value).intValue()); } else { try { if (compareCTC(tag, CTC_VOID)) { @@ -388,8 +265,8 @@ public class Javac { @Override public TypeKind getKind() { - if (Javac.compareCTC(tag, CTC_VOID)) return TypeKind.VOID; - if (Javac.compareCTC(tag, CTC_NONE)) return TypeKind.NONE; + if (tag == ((Integer) CTC_VOID.value).intValue()) return TypeKind.VOID; + if (tag == ((Integer) CTC_NONE.value).intValue()) return TypeKind.NONE; throw new AssertionError("Unexpected tag: " + tag); } @@ -468,30 +345,6 @@ public class Javac { } } - private static Method classDef; - - public static JCClassDecl ClassDef(TreeMaker maker, JCModifiers mods, Name name, List typarams, JCExpression extending, List implementing, List defs) { - if (classDef == null) try { - classDef = TreeMaker.class.getDeclaredMethod("ClassDef", JCModifiers.class, Name.class, List.class, JCExpression.class, List.class, List.class); - } catch (NoSuchMethodException ignore) {} - if (classDef == null) try { - classDef = TreeMaker.class.getDeclaredMethod("ClassDef", JCModifiers.class, Name.class, List.class, JCTree.class, List.class, List.class); - } catch (NoSuchMethodException ignore) {} - - if (classDef == null) throw new IllegalStateException("Lombok bug #20130617-1310: ClassDef doesn't look like anything we thought it would look like."); - if (!Modifier.isPublic(classDef.getModifiers()) && !classDef.isAccessible()) { - classDef.setAccessible(true); - } - - try { - return (JCClassDecl) classDef.invoke(maker, mods, name, typarams, extending, implementing, defs); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } catch (IllegalAccessException e) { - throw sneakyThrow(e.getCause()); - } - } - static RuntimeException sneakyThrow(Throwable t) { if (t == null) throw new NullPointerException("t"); Javac.sneakyThrow0(t); diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java new file mode 100644 index 00000000..916c8735 --- /dev/null +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -0,0 +1,662 @@ +/* + * Copyright (C) 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.javac; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; +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.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCArrayAccess; +import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; +import com.sun.tools.javac.tree.JCTree.JCAssert; +import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCAssignOp; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCBreak; +import com.sun.tools.javac.tree.JCTree.JCCase; +import com.sun.tools.javac.tree.JCTree.JCCatch; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCContinue; +import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; +import com.sun.tools.javac.tree.JCTree.JCErroneous; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCIf; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.JCTree.JCInstanceOf; +import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCParens; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; +import com.sun.tools.javac.tree.JCTree.JCReturn; +import com.sun.tools.javac.tree.JCTree.JCSkip; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCSwitch; +import com.sun.tools.javac.tree.JCTree.JCSynchronized; +import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; +import com.sun.tools.javac.tree.JCTree.JCTypeCast; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +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.TreeMaker; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; + +public class JavacTreeMaker { + private final TreeMaker tm; + + public JavacTreeMaker(TreeMaker tm) { + this.tm = tm; + } + + public JavacTreeMaker at(int pos) { + tm.at(pos); + return this; + } + + private static class MethodId { + private final String name; + private final Class returnType; + private final Class[] paramTypes; + + MethodId(String name, Class returnType, Class... types) { + 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); + } + + cache.putIfAbsent(fieldName, value); + return value; + } + + private static interface SchroedingerType {} + + public static class TypeTag implements SchroedingerType { + private static final ConcurrentMap TYPE_TAG_CACHE = new ConcurrentHashMap(); + public final Object value; + + private TypeTag(Object value) { + this.value = value; + } + + public static TypeTag typeTag(String identifier) { + return new TypeTag(getFieldCached(TYPE_TAG_CACHE, Javac.getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTags" : "com.sun.tools.javac.code.TypeTag", identifier)); + } + } + + public static class TreeTag implements SchroedingerType { + private static final ConcurrentMap TREE_TAG_CACHE = new ConcurrentHashMap(); + public final Object value; + + private TreeTag(Object value) { + this.value = value; + } + + 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)); + } + } + + /** + * Creates a new method ID based on the name of the method to invoke, the return type of that method, and the types of the parameters. + * + * A method matches if the return type matches, and for each parameter the following holds: + * + * 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); + } + + /** + * Creates a new method ID based on the name of a method in this class, assuming the name of the method to invoke in TreeMaker has the same name, + * the same return type, and the same parameters (under the same rules as the other MethodId method). + */ + static MethodId MethodId(String name) { + for (Method m : JavacTreeMaker.class.getDeclaredMethods()) { + if (m.getName().equals(name)) { + @SuppressWarnings("unchecked") Class r = (Class) m.getReturnType(); + Class[] p = m.getParameterTypes(); + return new MethodId(name, r, p); + } + } + + throw new InternalError("Not found: " + name); + } + + private static final ConcurrentHashMap, Method> METHOD_CACHE = new ConcurrentHashMap, Method>(); + private J invoke(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)); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } + + private static Method addToCache(MethodId m) { + Method found = null; + + outer: + for (Method method : TreeMaker.class.getDeclaredMethods()) { + if (!m.name.equals(method.getName())) continue; + Class[] t = method.getParameterTypes(); + if (t.length != m.paramTypes.length) continue; + for (int i = 0; i < t.length; i++) { + if (Symbol.class.isAssignableFrom(t[i])) continue outer; + if (!SchroedingerType.class.isAssignableFrom(m.paramTypes[i])) { + if (t[i].isPrimitive()) { + if (t[i] != m.paramTypes[i]) continue outer; + } else { + if (t[i].isAssignableFrom(m.paramTypes[i])) continue outer; + } + } + } + if (found == null) found = method; + else throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); + } + if (found == null) throw new IllegalStateException("Lombok TreeMaker frontedn issue: no match when looking for method: " + m); + found.setAccessible(true); + Object marker = METHOD_CACHE.putIfAbsent(m, found); + if (marker == null) return found; + return METHOD_CACHE.get(m); + } + + //javac versions: 6-8 + private static final MethodId TopLevel = MethodId("TopLevel"); + public JCCompilationUnit TopLevel(List packageAnnotations, JCExpression pid, List defs) { + return invoke(TopLevel, packageAnnotations, pid, defs); + } + + //javac versions: 6-8 + private static final MethodId Import = MethodId("Import"); + public JCImport Import(JCTree qualid, boolean staticImport) { + return invoke(Import, qualid, staticImport); + } + + //javac versions: 6-8 + private static final MethodId ClassDef = MethodId("ClassDef"); + public JCClassDecl ClassDef(JCModifiers mods, Name name, List typarams, JCExpression extending, List implementing, List defs) { + return invoke(ClassDef, mods, name, typarams, extending, implementing, defs); + } + + //javac versions: 6-8 + private static final MethodId MethodDef = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, List.class, List.class, JCBlock.class, JCExpression.class); + public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List typarams, List params, List thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDef, mods, name, resType, typarams, params, thrown, body, defaultValue); + } + + //javac versions: 8 + private static final MethodId MethodDefWithRecvParam = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, JCVariableDecl.class, List.class, List.class, JCBlock.class, JCExpression.class); + public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List typarams, JCVariableDecl recvparam, List params, List thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDefWithRecvParam, mods, name, resType, recvparam, typarams, params, thrown, body, defaultValue); + } + + //javac versions: 6-8 + private static final MethodId VarDef = MethodId("VarDef"); + public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init) { + return invoke(VarDef, mods, name, vartype, init); + } + + //javac versions: 8 + private static final MethodId ReceiverVarDef = MethodId("ReceiverVarDef"); + public JCVariableDecl ReceiverVarDef(JCModifiers mods, JCExpression name, JCExpression vartype) { + return invoke(ReceiverVarDef, mods, name, vartype); + } + + //javac versions: 6-8 + private static final MethodId Skip = MethodId("Skip"); + public JCSkip Skip() { + return invoke(Skip); + } + + //javac versions: 6-8 + private static final MethodId Block = MethodId("Block"); + public JCBlock Block(long flags, List stats) { + return invoke(Block, flags, stats); + } + + //javac versions: 6-8 + private static final MethodId DoLoop = MethodId("DoLoop"); + public JCDoWhileLoop DoLoop(JCStatement body, JCExpression cond) { + return invoke(DoLoop, body, cond); + } + + //javac versions: 6-8 + private static final MethodId WhileLoop = MethodId("WhileLoop"); + public JCWhileLoop WhileLoop(JCExpression cond, JCStatement body) { + return invoke(WhileLoop, cond, body); + } + + //javac versions: 6-8 + private static final MethodId ForLoop = MethodId("ForLoop"); + public JCForLoop ForLoop(List init, JCExpression cond, List step, JCStatement body) { + return invoke(ForLoop, init, cond, step, body); + } + + //javac versions: 6-8 + private static final MethodId ForeachLoop = MethodId("ForeachLoop"); + public JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body) { + return invoke(ForeachLoop, var, expr, body); + } + + //javac versions: 6-8 + private static final MethodId Labelled = MethodId("Labelled"); + public JCLabeledStatement Labelled(Name label, JCStatement body) { + return invoke(Labelled, label, body); + } + + //javac versions: 6-8 + private static final MethodId Switch = MethodId("Switch"); + public JCSwitch Switch(JCExpression selector, List cases) { + return invoke(Switch, selector, cases); + } + + //javac versions: 6-8 + private static final MethodId Case = MethodId("Case"); + public JCCase Case(JCExpression pat, List stats) { + return invoke(Case, pat, stats); + } + + //javac versions: 6-8 + private static final MethodId Synchronized = MethodId("Synchronized"); + public JCSynchronized Synchronized(JCExpression lock, JCBlock body) { + return invoke(Synchronized, lock, body); + } + + //javac versions: 6-8 + private static final MethodId Try = MethodId("Try", JCTry.class, JCBlock.class, List.class, JCBlock.class); + public JCTry Try(JCBlock body, List catchers, JCBlock finalizer) { + return invoke(Try, body, catchers, finalizer); + } + + //javac versions: 7-8 + private static final MethodId TryWithResources = MethodId("Try", JCTry.class, List.class, JCBlock.class, List.class, JCBlock.class); + public JCTry Try(List resources, JCBlock body, List catchers, JCBlock finalizer) { + return invoke(TryWithResources, resources, body, catchers, finalizer); + } + + //javac versions: 6-8 + private static final MethodId Catch = MethodId("Catch"); + public JCCatch Catch(JCVariableDecl param, JCBlock body) { + return invoke(Catch, param, body); + } + + //javac versions: 6-8 + private static final MethodId Conditional = MethodId("Conditional"); + public JCConditional Conditional(JCExpression cond, JCExpression thenpart, JCExpression elsepart) { + return invoke(Conditional, cond, thenpart, elsepart); + } + + //javac versions: 6-8 + private static final MethodId If = MethodId("If"); + public JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart) { + return invoke(If, cond, thenpart, elsepart); + } + + //javac versions: 6-8 + private static final MethodId Exec = MethodId("Exec"); + public JCExpressionStatement Exec(JCExpression expr) { + return invoke(Exec, expr); + } + + //javac versions: 6-8 + private static final MethodId Break = MethodId("Break"); + public JCBreak Break(Name label) { + return invoke(Break, label); + } + + //javac versions: 6-8 + private static final MethodId Continue = MethodId("Continue"); + public JCContinue Continue(Name label) { + return invoke(Continue, label); + } + + //javac versions: 6-8 + private static final MethodId Return = MethodId("Return"); + public JCReturn Return(JCExpression expr) { + return invoke(Return, expr); + } + + //javac versions: 6-8 + private static final MethodId Throw = MethodId("Throw"); + public JCThrow Throw(JCTree expr) { + return invoke(Throw, expr); + } + + //javac versions: 6-8 + private static final MethodId Assert = MethodId("Assert"); + public JCAssert Assert(JCExpression cond, JCExpression detail) { + return invoke(Assert, cond, detail); + } + + //javac versions: 6-8 + private static final MethodId Apply = MethodId("Apply"); + public JCMethodInvocation Apply(List typeargs, JCExpression fn, List args) { + return invoke(Apply, typeargs, fn, args); + } + + //javac versions: 6-8 + private static final MethodId NewClass = MethodId("NewClass"); + public JCNewClass NewClass(JCExpression encl, List typeargs, JCExpression clazz, List args, JCClassDecl def) { + return invoke(NewClass, encl, typeargs, clazz, args, def); + } + + //javac versions: 6-8 + private static final MethodId NewArray = MethodId("NewArray"); + public JCNewArray NewArray(JCExpression elemtype, List dims, List elems) { + return invoke(NewArray, elemtype, dims, elems); + } + + //javac versions: 8 +// private static final MethodId Lambda = MethodId("Lambda"); +// public JCLambda Lambda(List params, JCTree body) { +// return invoke(Lambda, params, body); +// } + + //javac versions: 6-8 + private static final MethodId Parens = MethodId("Parens"); + public JCParens Parens(JCExpression expr) { + return invoke(Parens, expr); + } + + //javac versions: 6-8 + private static final MethodId Assign = MethodId("Assign"); + public JCAssign Assign(JCExpression lhs, JCExpression rhs) { + return invoke(Assign, lhs, rhs); + } + + //javac versions: 6-8 + //opcode = [6-7] int [8] JCTree.Tag + private static final MethodId Assignop =