aboutsummaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/lombok/core/JavaIdentifiers.java57
-rw-r--r--src/utils/lombok/core/LombokImmutableList.java188
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java64
-rw-r--r--src/utils/lombok/javac/CommentCatcher.java40
-rw-r--r--src/utils/lombok/javac/CommentInfo.java2
-rw-r--r--src/utils/lombok/javac/JCNoTypeFactory.java11
-rw-r--r--src/utils/lombok/javac/Javac.java367
-rw-r--r--src/utils/lombok/javac/java6/CommentCollectingParserFactory.java2
-rw-r--r--src/utils/lombok/javac/java6/CommentCollectingScanner.java5
-rw-r--r--src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java37
-rw-r--r--src/utils/lombok/javac/java6/DocCommentScanner.java461
-rw-r--r--src/utils/lombok/javac/java7/CommentCollectingParserFactory.java4
-rw-r--r--src/utils/lombok/javac/java7/CommentCollectingScanner.java7
-rw-r--r--src/utils/lombok/javac/java7/CommentCollectingScannerFactory.java34
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