diff options
Diffstat (limited to 'src/utils')
| -rw-r--r-- | src/utils/lombok/core/JavaIdentifiers.java | 57 | ||||
| -rw-r--r-- | src/utils/lombok/core/LombokImmutableList.java | 188 | ||||
| -rw-r--r-- | src/utils/lombok/eclipse/Eclipse.java | 64 | ||||
| -rw-r--r-- | src/utils/lombok/javac/CommentCatcher.java | 40 | ||||
| -rw-r--r-- | src/utils/lombok/javac/CommentInfo.java | 2 | ||||
| -rw-r--r-- | src/utils/lombok/javac/JCNoTypeFactory.java | 11 | ||||
| -rw-r--r-- | src/utils/lombok/javac/Javac.java | 367 | ||||
| -rw-r--r-- | src/utils/lombok/javac/java6/CommentCollectingParserFactory.java | 2 | ||||
| -rw-r--r-- | src/utils/lombok/javac/java6/CommentCollectingScanner.java | 5 | ||||
| -rw-r--r-- | src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java | 37 | ||||
| -rw-r--r-- | src/utils/lombok/javac/java6/DocCommentScanner.java | 461 | ||||
| -rw-r--r-- | src/utils/lombok/javac/java7/CommentCollectingParserFactory.java | 4 | ||||
| -rw-r--r-- | src/utils/lombok/javac/java7/CommentCollectingScanner.java | 7 | ||||
| -rw-r--r-- | src/utils/lombok/javac/java7/CommentCollectingScannerFactory.java | 34 |
14 files changed, 1140 insertions, 139 deletions
diff --git a/src/utils/lombok/core/JavaIdentifiers.java b/src/utils/lombok/core/JavaIdentifiers.java new file mode 100644 index 00000000..cbe90eed --- /dev/null +++ b/src/utils/lombok/core/JavaIdentifiers.java @@ -0,0 +1,57 @@ +/* + * 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.core; + +/** + * Utility functions for validating potential java verifiers. + */ +public class JavaIdentifiers { + private JavaIdentifiers() {} + + private static final LombokImmutableList<String> KEYWORDS = LombokImmutableList.of( + "public", "private", "protected", + "default", "switch", "case", + "for", "do", "goto", "const", "strictfp", "while", "if", "else", + "byte", "short", "int", "long", "float", "double", "void", "boolean", "char", + "null", "false", "true", + "continue", "break", "return", "instanceof", + "synchronized", "volatile", "transient", "final", "static", + "interface", "class", "extends", "implements", "throws", + "throw", "catch", "try", "finally", "abstract", "assert", + "enum", "import", "package", "native", "new", "super", "this"); + + public static boolean isValidJavaIdentifier(String identifier) { + if (identifier == null) return false; + if (identifier.isEmpty()) return false; + + if (!Character.isJavaIdentifierStart(identifier.charAt(0))) return false; + for (int i = 1; i < identifier.length(); i++) { + if (!Character.isJavaIdentifierPart(identifier.charAt(i))) return false; + } + + return !isKeyword(identifier); + } + + public static boolean isKeyword(String keyword) { + return KEYWORDS.contains(keyword); + } +} diff --git a/src/utils/lombok/core/LombokImmutableList.java b/src/utils/lombok/core/LombokImmutableList.java new file mode 100644 index 00000000..e0e1136c --- /dev/null +++ b/src/utils/lombok/core/LombokImmutableList.java @@ -0,0 +1,188 @@ +/* + * 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.core; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +public final class LombokImmutableList<T> implements Iterable<T> { + private Object[] content; + private static final LombokImmutableList<?> EMPTY = new LombokImmutableList<Object>(new Object[0]); + + @SuppressWarnings("unchecked") + public static <T> LombokImmutableList<T> of() { + return (LombokImmutableList<T>) EMPTY; + } + + public static <T> LombokImmutableList<T> of(T a) { + return new LombokImmutableList<T>(new Object[] {a}); + } + + public static <T> LombokImmutableList<T> of(T a, T b) { + return new LombokImmutableList<T>(new Object[] {a, b}); + } + + public static <T> LombokImmutableList<T> of(T a, T b, T c) { + return new LombokImmutableList<T>(new Object[] {a, b, c}); + } + + public static <T> LombokImmutableList<T> of(T a, T b, T c, T d) { + return new LombokImmutableList<T>(new Object[] {a, b, c, d}); + } + + public static <T> LombokImmutableList<T> of(T a, T b, T c, T d, T e) { + return new LombokImmutableList<T>(new Object[] {a, b, c, d, e}); + } + + public static <T> LombokImmutableList<T> of(T a, T b, T c, T d, T e, T f, T... g) { + Object[] rest = g == null ? new Object[] {null} : g; + Object[] val = new Object[rest.length + 6]; + System.arraycopy(rest, 0, val, 6, rest.length); + val[0] = a; + val[1] = b; + val[2] = c; + val[3] = d; + val[4] = e; + val[5] = f; + return new LombokImmutableList<T>(val); + } + + public static <T> LombokImmutableList<T> copyOf(Collection<? extends T> list) { + return new LombokImmutableList<T>(list.toArray()); + } + + public static <T> LombokImmutableList<T> copyOf(Iterable<? extends T> iterable) { + List<T> list = new ArrayList<T>(); + for (T o : iterable) list.add(o); + return copyOf(list); + } + + private LombokImmutableList(Object[] content) { + this.content = content; + } + + public LombokImmutableList<T> replaceElementAt(int idx, T newValue) { + Object[] newContent = content.clone(); + newContent[idx] = newValue; + return new LombokImmutableList<T>(newContent); + } + + public LombokImmutableList<T> append(T newValue) { + int len = content.length; + Object[] newContent = new Object[len + 1]; + System.arraycopy(content, 0, newContent, 0, len); + newContent[len] = newValue; + return new LombokImmutableList<T>(newContent); + } + + public LombokImmutableList<T> prepend(T newValue) { + int len = content.length; + Object[] newContent = new Object[len + 1]; + System.arraycopy(content, 0, newContent, 1, len); + newContent[0] = newValue; + return new LombokImmutableList<T>(newContent); + } + + public int indexOf(T val) { + int len = content.length; + if (val == null) { + for (int i = 0; i < len; i++) if (content[i] == null) return i; + return -1; + } + + for (int i = 0; i < len; i++) if (val.equals(content[i])) return i; + return -1; + } + + public LombokImmutableList<T> removeElement(T val) { + int idx = indexOf(val); + return idx == -1 ? this : removeElementAt(idx); + } + + public LombokImmutableList<T> removeElementAt(int idx) { + int len = content.length; + Object[] newContent = new Object[len - 1]; + if (idx > 0) System.arraycopy(content, 0, newContent, 0, idx); + if (idx < len - 1) System.arraycopy(content, idx + 1, newContent, idx, len - idx - 1); + return new LombokImmutableList<T>(newContent); + } + + public boolean isEmpty() { + return content.length == 0; + } + + public int size() { + return content.length; + } + + @SuppressWarnings("unchecked") + public T get(int idx) { + return (T) content[idx]; + } + + public boolean contains(T in) { + if (in == null) { + for (Object e : content) if (e == null) return true; + return false; + } + + for (Object e : content) if (in.equals(e)) return true; + return false; + } + + public Iterator<T> iterator() { + return new Iterator<T>() { + private int idx = 0; + @Override public boolean hasNext() { + return idx < content.length; + } + + @SuppressWarnings("unchecked") + @Override public T next() { + if (idx < content.length) return (T) content[idx++]; + throw new NoSuchElementException(); + } + + @Override public void remove() { + throw new UnsupportedOperationException("List is immutable"); + } + }; + } + + @Override public String toString() { + return Arrays.toString(content); + } + + @Override public boolean equals(Object obj) { + if (!(obj instanceof LombokImmutableList)) return false; + if (obj == this) return true; + return Arrays.equals(content, ((LombokImmutableList<?>) obj).content); + } + + @Override public int hashCode() { + return Arrays.hashCode(content); + } +} diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index 301925d1..c2a863d5 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -21,6 +21,7 @@ */ package lombok.eclipse; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -36,8 +37,11 @@ import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.Literal; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; public class Eclipse { @@ -58,7 +62,9 @@ public class Eclipse { * but we need to deal with it. This turns [[java][lang][String]] into "java.lang.String". */ public static String toQualifiedName(char[][] typeName) { - StringBuilder sb = new StringBuilder(); + int len = typeName.length - 1; + for (char[] c : typeName) len += c.length; + StringBuilder sb = new StringBuilder(len); boolean first = true; for (char[] c : typeName) { sb.append(first ? "" : ".").append(c); @@ -175,4 +181,58 @@ public class Eclipse { return null; } + + private static long latestEcjCompilerVersionConstantCached = 0; + + public static long getLatestEcjCompilerVersionConstant() { + if (latestEcjCompilerVersionConstantCached != 0) return latestEcjCompilerVersionConstantCached; + + int highestVersionSoFar = 0; + for (Field f : ClassFileConstants.class.getDeclaredFields()) { + try { + if (f.getName().startsWith("JDK1_")) { + int thisVersion = Integer.parseInt(f.getName().substring("JDK1_".length())); + if (thisVersion > highestVersionSoFar) { + highestVersionSoFar = thisVersion; + latestEcjCompilerVersionConstantCached = (Long) f.get(null); + } + } + } catch (Exception ignore) {} + } + + if (highestVersionSoFar > 6 && !ecjSupportsJava7Features()) { + latestEcjCompilerVersionConstantCached = ClassFileConstants.JDK1_6; + } + return latestEcjCompilerVersionConstantCached; + } + + private static int ecjCompilerVersionCached = -1; + public static int getEcjCompilerVersion() { + if (ecjCompilerVersionCached >= 0) return ecjCompilerVersionCached; + + for (Field f : CompilerOptions.class.getDeclaredFields()) { + try { + if (f.getName().startsWith("VERSION_1_")) { + ecjCompilerVersionCached = Math.max(ecjCompilerVersionCached, Integer.parseInt(f.getName().substring("VERSION_1_".length()))); + } + } catch (Exception ignore) {} + } + + if (ecjCompilerVersionCached < 5) ecjCompilerVersionCached = 5; + if (!ecjSupportsJava7Features()) ecjCompilerVersionCached = Math.min(6, ecjCompilerVersionCached); + return ecjCompilerVersionCached; + } + + /** + * Certain ECJ versions that only go up to -source 6 report that they support -source 7 and even fail to error when -source 7 is applied. + * We detect this and correctly say that no more than -source 6 is supported. (when this is the case, this method returns false). + */ + private static boolean ecjSupportsJava7Features() { + try { + TryStatement.class.getDeclaredField("resources"); + return true; + } catch (NoSuchFieldException e) { + return false; + } + } } diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index e3754627..8d1e71c0 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Project Lombok Authors. + * Copyright (C) 2011-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 @@ -21,9 +21,12 @@ */ package lombok.javac; +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; @@ -62,36 +65,33 @@ public class CommentCatcher { private static void registerCommentsCollectingScannerFactory(Context context) { try { - if (JavaCompiler.version().startsWith("1.6")) { - Class.forName("lombok.javac.java6.CommentCollectingScannerFactory").getMethod("preRegister", Context.class).invoke(null, context); - } 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); + Class<?> scannerFactory; + if (Javac.getJavaCompilerVersion() <= 6) { + scannerFactory = Class.forName("lombok.javac.java6.CommentCollectingScannerFactory"); } else { - throw new IllegalStateException("No comments parser for compiler version " + JavaCompiler.version()); + scannerFactory = Class.forName("lombok.javac.java7.CommentCollectingScannerFactory"); } + scannerFactory.getMethod("preRegister", Context.class).invoke(null, context); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException)e; - throw new RuntimeException(e); + throw Lombok.sneakyThrow(e); } } private static void setInCompiler(JavaCompiler compiler, Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) { - try { - 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 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); + Class<?> parserFactory; + if (Javac.getJavaCompilerVersion() <= 6) { + parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory"); } else { - throw new IllegalStateException("No comments parser for compiler version " + JavaCompiler.version()); + parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory"); } - + parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException)e; - throw new RuntimeException(e); + throw Lombok.sneakyThrow(e); } } - } diff --git a/src/utils/lombok/javac/CommentInfo.java b/src/utils/lombok/javac/CommentInfo.java index 7375d51a..afdd8469 100644 --- a/src/utils/lombok/javac/CommentInfo.java +++ b/src/utils/lombok/javac/CommentInfo.java @@ -66,7 +66,7 @@ public final class CommentInfo { } public boolean isJavadoc() { - return content.startsWith("/**"); + return content.startsWith("/**") && content.length() > 4; } @Override diff --git a/src/utils/lombok/javac/JCNoTypeFactory.java b/src/utils/lombok/javac/JCNoTypeFactory.java deleted file mode 100644 index e7be7665..00000000 --- a/src/utils/lombok/javac/JCNoTypeFactory.java +++ /dev/null @@ -1,11 +0,0 @@ -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 9f2936a8..dfa51e00 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -21,19 +21,38 @@ */ package lombok.javac; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Objects; +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; +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.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.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCUnary; import com.sun.tools.javac.tree.TreeMaker; +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. @@ -46,6 +65,30 @@ public class Javac { /** 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 VERSION_PARSER = Pattern.compile("^(\\d{1,6})\\.(\\d{1,6}).*$"); + + private static final AtomicInteger compilerVersion = new AtomicInteger(-1); + + /** + * Returns the version of this java compiler, i.e. the JDK that it shipped in. For example, for javac v1.7, this returns {@code 7}. + */ + public static int getJavaCompilerVersion() { + int cv = compilerVersion.get(); + if (cv != -1) return cv; + Matcher m = VERSION_PARSER.matcher(JavaCompiler.version()); + if (m.matches()) { + int major = Integer.parseInt(m.group(1)); + int minor = Integer.parseInt(m.group(2)); + if (major == 1) { + compilerVersion.set(minor); + return minor; + } + } + + compilerVersion.set(6); + return 6; + } + /** * Checks if the given expression (that really ought to refer to a type * expression) represents a primitive type. @@ -102,56 +145,53 @@ public class Javac { public static final Object CTC_EQUAL = getTreeTag("EQ"); public static boolean compareCTC(Object ctc1, Object ctc2) { - return Objects.equals(ctc1, ctc2); + return ctc1 == null ? ctc2 == null : ctc1.equals(ctc2); } + private static final ConcurrentMap<String, Object> TYPE_TAG_CACHE = new ConcurrentHashMap<String, Object>(); + private static final ConcurrentMap<String, Object> TREE_TAG_CACHE = new ConcurrentHashMap<String, Object>(); + + /** - * 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 <code>com.sun.tools.javac.code.TypeTag</code> - * for JDK 7 and lower, this is the value of the constant within <code>com.sun.tools.javac.code.TypeTags</code> + * Retrieves the provided TypeTag value, in a compiler version independent manner. * + * The actual type object differs depending on the Compiler version: + * <ul> + * <li>For JDK 8 this is an enum value of type <code>com.sun.tools.javac.code.TypeTag</code> + * <li>for JDK 7 and lower, this is the value of the constant within <code>com.sun.tools.javac.code.TypeTags</code> + * </ul> * 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 + * @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) { - try { - 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); - } + return getFieldCached(TYPE_TAG_CACHE, getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTag" : "com.sun.tools.javac.code.TypeTags", identifier); } 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); - } + return getFieldCached(TREE_TAG_CACHE, getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.tree.JCTree" : "com.sun.tools.javac.tree.JCTree$Tag", identifier); + } + + private static Object getFieldCached(ConcurrentMap<String, Object> 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 new RuntimeException(e); + throw Lombok.sneakyThrow(e); } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException) e; - throw new RuntimeException(e); + throw Lombok.sneakyThrow(e); + } catch (ClassNotFoundException e) { + throw Lombok.sneakyThrow(e); } + + cache.putIfAbsent(fieldName, value); + return value; } - + public static Object getTreeTypeTag(JCPrimitiveTypeTree tree) { return tree.typetag; } @@ -159,82 +199,239 @@ public class Javac { public static Object getTreeTypeTag(JCLiteral tree) { return tree.typetag; } + + private static final Method createIdent, createLiteral, createUnary, createBinary; + 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.code.TypeTag", 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.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); + } + } + + private static Method getMethod(Class<?> clazz, String name, String... paramTypes) { + try { + Class<?>[] c = new Class[paramTypes.length]; + 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); + } catch (ClassNotFoundException e) { + throw Lombok.sneakyThrow(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); + throw Lombok.sneakyThrow(e); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); } } 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); + throw Lombok.sneakyThrow(e); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); } } 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); + throw Lombok.sneakyThrow(e); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); } } - public static JCBinary makeBinary(TreeMaker maker, Object ctc, JCExpression rhsArgument, JCExpression lhsArgument) { + public static JCBinary makeBinary(TreeMaker maker, Object ctc, JCExpression lhsArgument, JCExpression rhsArgument) { 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); + return (JCBinary) createBinary.invoke(maker, ctc, lhsArgument, rhsArgument); } catch (IllegalAccessException e) { - throw new RuntimeException(e); + throw Lombok.sneakyThrow(e); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); + } + } + + private static final Class<?> JC_VOID_TYPE, JC_NO_TYPE; + + static { + Class<?> c = null; + try { + c = Class.forName("com.sun.tools.javac.code.Type$JCVoidType"); + } catch (Exception ignore) {} + JC_VOID_TYPE = c; + c = null; + try { + c = Class.forName("com.sun.tools.javac.code.Type$JCNoType"); + } catch (Exception ignore) {} + JC_NO_TYPE = c; + } + + public static Type createVoidType(TreeMaker maker, Object tag) { + if (Javac.getJavaCompilerVersion() < 8) { + return new JCNoType(((Integer) tag).intValue()); + } else { + try { + if (compareCTC(tag, CTC_VOID)) { + return (Type) JC_VOID_TYPE.newInstance(); + } else { + return (Type) JC_NO_TYPE.newInstance(); + } + } catch (IllegalAccessException e) { + throw Lombok.sneakyThrow(e); + } catch (InstantiationException e) { + throw Lombok.sneakyThrow(e); + } + } + } + + private static class JCNoType extends Type implements NoType { + public JCNoType(int tag) { + super(tag, null); + } + + @Override + public TypeKind getKind() { + if (Javac.compareCTC(tag, CTC_VOID)) return TypeKind.VOID; + if (Javac.compareCTC(tag, CTC_NONE)) return TypeKind.NONE; + throw new AssertionError("Unexpected tag: " + tag); + } + + @Override + public <R, P> R accept(TypeVisitor<R, P> v, P p) { + return v.visitNoType(this, p); + } + } + + private static final Field JCTREE_TAG, JCLITERAL_TYPETAG, JCPRIMITIVETYPETREE_TYPETAG; + private static final Method JCTREE_GETTAG; + 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; + + 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) { - if (e instanceof RuntimeException) throw (RuntimeException) e; - throw new RuntimeException(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"); + } + } + + private static Method classDef; + + public static JCClassDecl ClassDef(TreeMaker maker, JCModifiers mods, Name name, List<JCTypeParameter> typarams, JCExpression extending, List<JCExpression> implementing, List<JCTree> defs) { + if (classDef == null) try { + classDef = TreeMaker.class.getDeclaredMethod |
