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("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());
+ }
+ }
+
+ private static RuntimeException sneakyThrow(Throwable t) {
+ if (t == null) throw new NullPointerException("t");
+ Javac.<RuntimeException>sneakyThrow0(t);
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T {
+ throw (T)t;
+ }
}
diff --git a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java
index b2a248c8..7e34b723 100644
--- a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java
+++ b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java
@@ -25,7 +25,7 @@ public class CommentCollectingParserFactory extends Parser.Factory {
}
@Override public Parser newParser(Lexer S, boolean keepDocComments, boolean genEndPos) {
- Object x = new CommentCollectingParser(this, S, keepDocComments, commentsMap);
+ Object x = new CommentCollectingParser(this, S, true, commentsMap);
return (Parser) x;
// CCP is based on a stub which extends nothing, but at runtime the stub is replaced with either
//javac6's EndPosParser which extends Parser, or javac7's EndPosParser which implements Parser.
diff --git a/src/utils/lombok/javac/java6/CommentCollectingScanner.java b/src/utils/lombok/javac/java6/CommentCollectingScanner.java
index 66e1514d..b584ec16 100644
--- a/src/utils/lombok/javac/java6/CommentCollectingScanner.java
+++ b/src/utils/lombok/javac/java6/CommentCollectingScanner.java
@@ -27,12 +27,10 @@ import lombok.javac.CommentInfo;
import lombok.javac.CommentInfo.EndConnection;
import lombok.javac.CommentInfo.StartConnection;
-import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
-
-public class CommentCollectingScanner extends Scanner {
+public class CommentCollectingScanner extends DocCommentScanner {
private final ListBuffer<CommentInfo> comments = ListBuffer.lb();
private int endComment = 0;
@@ -56,6 +54,7 @@ public class CommentCollectingScanner extends Scanner {
CommentInfo comment = new CommentInfo(prevEndPos, pos, endPos, content, start, end);
comments.append(comment);
+ super.processComment(style);
}
private EndConnection determineEndConnection(int pos) {
diff --git a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java
index 30acbd5a..f3d6bd72 100644
--- a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java
+++ b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.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
@@ -26,19 +26,44 @@ import java.nio.CharBuffer;
import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.util.Context;
-public class CommentCollectingScannerFactory extends Scanner.Factory {
+public class CommentCollectingScannerFactory extends DocCommentScanner.Factory {
+ @SuppressWarnings("all")
public static void preRegister(final Context context) {
if (context.get(scannerFactoryKey) == null) {
- context.put(scannerFactoryKey, new Context.Factory<Scanner.Factory>() {
- public CommentCollectingScanner.Factory make() {
+ // Careful! There is voodoo magic here!
+ //
+ // Context.Factory is parameterized. make() is for javac6 and below; make(Context) is for javac7 and up.
+ // this anonymous inner class definition is intentionally 'raw' - the return type of both 'make' methods is 'T',
+ // which means the compiler will only generate the correct "real" override method (with returntype Object, which is
+ // the lower bound for T, as a synthetic accessor for the make with returntype ScannerFactory) for that make method which
+ // is actually on the classpath (either make() for javac6-, or make(Context) for javac7+).
+ //
+ // We normally solve this issue via src/stubs, with BOTH make methods listed, but for some reason the presence of a stubbed out
+ // Context (or even a complete copy, it doesn't matter) results in a really strange eclipse bug, where any mention of any kind
+ // of com.sun.tools.javac.tree.TreeMaker in a source file disables ALL usage of 'go to declaration' and auto-complete in the entire
+ // source file.
+ //
+ // Thus, in short:
+ // * Do NOT parameterize the anonymous inner class literal.
+ // * Leave the return types as 'j.l.Object'.
+ // * Leave both make methods intact; deleting one has no effect on javac6- / javac7+, but breaks the other. Hard to test for.
+ // * Do not stub com.sun.tools.javac.util.Context or any of its inner types, like Factory.
+ @SuppressWarnings("all")
+ class MyFactory implements Context.Factory {
+ // This overrides the javac6- version of make.
+ public Object make() {
return new CommentCollectingScannerFactory(context);
}
- public CommentCollectingScanner.Factory make(Context c) {
+ // This overrides the javac7+ version of make.
+ public Object make(Context c) {
return new CommentCollectingScannerFactory(c);
}
- });
+ }
+
+ @SuppressWarnings("unchecked") Context.Factory<Scanner.Factory> factory = new MyFactory();
+ context.put(scannerFactoryKey, factory);
}
}
diff --git a/src/utils/lombok/javac/java6/DocCommentScanner.java b/src/utils/lombok/javac/java6/DocCommentScanner.java
new file mode 100644
index 00000000..ff3eadd4
--- /dev/null
+++ b/src/utils/lombok/javac/java6/DocCommentScanner.java
@@ -0,0 +1,461 @@
+package lombok.javac.java6;
+
+/*
+ * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import static com.sun.tools.javac.util.LayoutCharacters.*;
+
+import java.nio.CharBuffer;
+
+import com.sun.tools.javac.parser.Scanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Position;
+
+/** An extension to the base lexical analyzer that captures
+ * and processes the contents of doc comments. It does so by
+ * translating Unicode escape sequences and by stripping the
+ * leading whitespace and starts from each line of the comment.
+ *
+ * <p><b>This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+public class DocCommentScanner extends Scanner {
+
+ /** A factory for creating scanners. */
+ public static class Factory extends Scanner.Factory {
+
+ @SuppressWarnings({"unchecked", "all"})
+ public static void preRegister(final Context context) {
+ context.put(scannerFactoryKey, new Context.Factory() {
+ public Object make() {
+ return new Factory(context);
+ }
+
+ public Object make(Context c) {
+ return new Factory(c);
+ }
+ });
+ }
+
+ /** Create a new scanner factory. */
+ protected Factory(Context context) {
+ super(context);
+ }
+
+ @Override
+ public Scanner newScanner(CharSequence input) {
+ if (input instanceof CharBuffer) {
+ return new DocCommentScanner(this, (CharBuffer)input);
+ } else {
+ char[] array = input.toString().toCharArray();
+ return newScanner(array, array.length);
+ }
+ }
+
+ @Override
+ public Scanner newScanner(char[] input, int inputLength) {
+ return new DocCommentScanner(this, input, inputLength);
+ }
+ }
+
+
+ /** Create a scanner from the input buffer. buffer must implement
+ * array() and compact(), and remaining() must be less than limit().
+ */
+ protected DocCommentScanner(Factory fac, CharBuffer buffer) {
+ super(fac, buffer);
+ }
+
+ /** Create a scanner from the input array. The array must have at
+ * least a single character of extra space.
+ */
+ protected DocCommentScanner(Factory fac, char[] input, int inputLength) {
+ super(fac, input, inputLength);
+ }
+
+ /** Starting position of the comment in original source
+ */
+ private int pos;
+
+ /** The comment input buffer, index of next chacter to be read,
+ * index of one past last character in buffer.
+ */
+ private char[] buf;
+ private int bp;
+ private int buflen;
+
+ /** The current character.
+ */
+ private char ch;
+
+ /** The column number position of the current character.
+ */
+ private int col;
+
+ /** The buffer index of the last converted Unicode character
+ */
+ private int unicodeConversionBp = 0;
+
+ /**
+ * Buffer for doc comment.
+ */
+ private char[] docCommentBuffer = new char[1024];
+
+ /**
+ * Number of characters in doc comment buffer.
+ */
+ private int docCommentCount;
+
+ /**
+ * Translated and stripped contents of doc comment
+ */
+ private String docComment = null;
+
+
+ /** Unconditionally expand the comment buffer.
+ */
+ private void expandCommentBuffer() {
+ char[] newBuffer = new char[docCommentBuffer.length * 2];
+ System.arraycopy(docCommentBuffer, 0, newBuffer,
+ 0, docCommentBuffer.length);
+ docCommentBuffer = newBuffer;
+ }
+
+ /** Convert an ASCII digit from its base (8, 10, or 16)
+ * to its value.
+ */
+ private int digit(int base) {
+ char c = ch;
+ int result = Character.digit(c, base);
+ if (result >= 0 && c > 0x7f) {
+ ch = "0123456789abcdef".charAt(result);
+ }
+ return result;
+ }
+
+ /** Convert Unicode escape; bp points to initial '\' character
+ * (Spec 3.3).
+ */
+ private void convertUnicode() {
+ if (ch == '\\' && unicodeConversionBp != bp) {
+ bp++; ch = buf[bp]; col++;
+ if (ch == 'u') {
+ do {
+ bp++; ch = buf[bp]; col++;
+ } while (ch == 'u');
+ int limit = bp + 3;
+ if (limit < buflen) {
+ int d = digit(16);
+ int code = d;
+ while (bp < limit && d >= 0) {
+ bp++; ch = buf[bp]; col++;
+ d = digit(16);
+ code = (code << 4) + d;
+ }
+ if (d >= 0) {
+ ch = (char)code;
+ unicodeConversionBp = bp;
+ return;
+ }
+ }
+ // "illegal.Unicode.esc", reported by base scanner
+ } else {
+ bp--;
+ ch = '\\';
+ col--;
+ }
+ }
+ }
+
+
+ /** Read next character.
+ */
+ private void scanChar() {
+ bp++;
+ ch = buf[bp];
+ switch (ch) {
+ case '\r': // return
+ col = 0;
+ break;
+ case '\n': // newline
+ if (bp == 0 || buf[bp-1] != '\r') {
+ col = 0;
+ }
+ break;
+ case '\t': // tab
+ col = (col / TabInc * TabInc) + TabInc;
+ break;
+ case '\\': // possible Unicode
+ col++;
+ convertUnicode();
+ break;
+ default:
+ col++;
+ break;
+ }
+ }
+
+ /**
+ * Read next character in doc comment, skipping over double '\' characters.
+ * If a double '\' is skipped, put in the buffer and update buffer count.
+ */
+ private void scanDocCommentChar() {
+ scanChar();
+ if (ch == '\\') {
+ if (buf[bp+1] == '\\' && unicodeConversionBp != bp) {
+ if (docCommentCount == docCommentBuffer.length)
+ expandCommentBuffer();
+ docCommentBuffer[docCommentCount++] = ch;
+ bp++; col++;
+ } else {
+ convertUnicode();
+ }
+ }
+ }
+
+ /* Reset doc comment before reading each new token
+ */
+ public void nextToken() {
+ docComment = null;
+ super.nextToken();
+ }
+
+ /**
+ * Returns the documentation string of the current token.
+ */
+ public String docComment() {
+ return docComment;
+ }
+
+ /**
+ * Process a doc comment and make the string content available.
+ * Strips leading whitespace and stars.
+ */
+ @SuppressWarnings("fallthrough")
+ protected void processComment(CommentStyle style) {
+ if (style != CommentStyle.JAVADOC) {
+ return;
+ }
+
+ pos = pos();
+ buf = getRawCharacters(pos, endPos());
+ buflen = buf.length;
+ bp = 0;
+ col = 0;
+
+ docCommentCount = 0;
+
+ boolean firstLine = true;
+
+ // Skip over first slash
+ scanDocCommentChar();
+ // Skip over first star
+ scanDocCommentChar();
+
+ // consume any number of stars
+ while (bp < buflen && ch == '*') {
+ scanDocCommentChar();
+ }
+ // is the comment in the form /**/, /***/, /****/, etc. ?
+ if (bp < buflen && ch == '/') {
+ docComment = "";
+ return;
+ }
+
+ // skip a newline on the first line of the comment.
+ if (bp < buflen) {
+ if (ch == LF) {
+ scanDocCommentChar();
+ firstLine = false;
+ } else if (ch == CR) {
+ scanDocCommentChar();
+ if (ch == LF) {
+ scanDocCommentChar();
+ firstLine = false;
+ }
+ }
+ }
+
+ outerLoop:
+
+ // The outerLoop processes the doc comment, looping once
+ // for each line. For each line, it first strips off
+ // whitespace, then it consumes any stars, then it
+ // puts the rest of the line into our buffer.
+ while (bp < buflen) {
+
+ // The wsLoop consumes whitespace from the beginning
+ // of each line.
+ wsLoop:
+
+ while (bp < buflen) {
+ switch(ch) {
+ case ' ':
+ scanDocCommentChar();
+ break;
+ case '\t':
+ col = ((col - 1) / TabInc * TabInc) + TabInc;
+ scanDocCommentChar();
+ break;
+ case FF:
+ col = 0;
+ scanDocCommentChar();
+ break;
+// Treat newline at beginning of line (blank line, no star)
+// as comment text. Old Javadoc compatibility requires this.
+/*---------------------------------*
+ case CR: // (Spec 3.4)
+ scanDocCommentChar();
+ if (ch == LF) {
+ col = 0;
+ scanDocCommentChar();
+ }
+ break;
+ case LF: // (Spec 3.4)
+ scanDocCommentChar();
+ break;
+*---------------------------------*/
+ default:
+ // we've seen something that isn't whitespace;
+ // jump out.
+ break wsLoop;
+ }
+ }
+
+ // Are there stars here? If so, consume them all
+ // and check for the end of comment.
+ if (ch == '*') {
+ // skip all of the stars
+ do {
+ scanDocCommentChar();
+ } while (ch == '*');
+
+ // check for the closing slash.
+ if (ch == '/') {
+ // We're done with the doc comment
+ // scanChar() and breakout.
+ break outerLoop;
+ }
+ } else if (! firstLine) {
+ //The current line does not begin with a '*' so we will indent it.
+ for (int i = 1; i < col; i++) {
+ if (docCommentCount == docCommentBuffer.length)
+ expandCommentBuffer();
+ docCommentBuffer[docCommentCount++] = ' ';
+ }
+ }
+
+ // The textLoop processes the rest of the characters
+ // on the line, adding them to our buffer.
+ textLoop:
+ while (bp < buflen) {
+ switch (ch) {
+ case '*':
+ // Is this just a star? Or is this the
+ // end of a comment?
+ scanDocCommentChar();
+ if (ch == '/') {
+ // This is the end of the comment,
+ // set ch and return our buffer.
+ break outerLoop;
+ }
+ // This is just an ordinary star. Add it to
+ // the buffer.
+ if (docCommentCount == docCommentBuffer.length)
+ expandCommentBuffer();
+ docCommentBuffer[docCommentCount++] = '*';
+ break;
+ case ' ':
+ case '\t':
+ if (docCommentCount == docCommentBuffer.length)
+ expandCommentBuffer();
+ docCommentBuffer[docCommentCount++] = ch;
+ scanDocCommentChar();
+ break;
+ case FF:
+ scanDocCommentChar();
+ break textLoop; // treat as end of line
+ case CR: // (Spec 3.4)
+ scanDocCommentChar();
+ if (ch != LF) {
+ // Canonicalize CR-only line terminator to LF
+ if (docCommentCount == docCommentBuffer.length)
+ expandCommentBuffer();
+ docCommentBuffer[docCommentCount++] = (char)LF;
+ break textLoop;
+ }
+ /* fall through to LF case */
+ case LF: // (Spec 3.4)
+ // We've seen a newline. Add it to our
+ // buffer and break out of this loop,
+ // starting fresh on a new line.
+ if (docCommentCount == docCommentBuffer.length)
+ expandCommentBuffer();
+ docCommentBuffer[docCommentCount++] = ch;
+ scanDocCommentChar();
+ break textLoop;
+ default:
+ // Add the character to our buffer.
+ if (docCommentCount == docCommentBuffer.length)
+ expandCommentBuffer();
+ docCommentBuffer[docCommentCount++] = ch;
+ scanDocCommentChar();
+ }
+ } // end textLoop
+ firstLine = false;
+ } // end outerLoop
+
+ if (docCommentCount > 0) {
+ int i = docCommentCount - 1;
+ trailLoop:
+ while (i > -1) {
+ switch (docCommentBuffer[i]) {
+ case '*':
+ i--;
+ break;
+ default:
+ break trailLoop;
+ }
+ }
+ docCommentCount = i + 1;
+
+ // Store the text of the doc comment
+ docComment = new String(docCommentBuffer, 0 , docCommentCount);
+ } else {
+ docComment = "";
+ }
+ }
+
+ /** Build a map for translating between line numbers and
+ * positions in the input.
+ *
+ * @return a LineMap */
+ public Position.LineMap getLineMap() {
+ char[] buf = getRawCharacters();
+ return Position.makeLineMap(buf, buf.length, true);
+ }
+}
diff --git a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java
index e361a5bd..e9575c14 100644
--- a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java
+++ b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java
@@ -30,8 +30,8 @@ public class CommentCollectingParserFactory extends ParserFactory {
public Parser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) {
ScannerFactory scannerFactory = ScannerFactory.instance(context);
- Lexer lexer = scannerFactory.newScanner(input, keepDocComments);
- Object x = new CommentCollectingParser(this, lexer, keepDocComments, keepLineMap, commentsMap);
+ Lexer lexer = scannerFactory.newScanner(input, true);
+ Object x = new CommentCollectingParser(this, lexer, true, keepLineMap, commentsMap);
return (Parser) x;
// CCP is based on a stub which extends nothing, but at runtime the stub is replaced with either
//javac6's EndPosParser which extends Parser, or javac7's EndPosParser which implements Parser.
diff --git a/src/utils/lombok/javac/java7/CommentCollectingScanner.java b/src/utils/lombok/javac/java7/CommentCollectingScanner.java
index e2d040f2..6ebd3ac1 100644
--- a/src/utils/lombok/javac/java7/CommentCollectingScanner.java
+++ b/src/utils/lombok/javac/java7/CommentCollectingScanner.java
@@ -26,12 +26,12 @@ import java.nio.CharBuffer;
import lombok.javac.CommentInfo;
import lombok.javac.CommentInfo.EndConnection;
import lombok.javac.CommentInfo.StartConnection;
+
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.parser.DocCommentScanner;
-import com.sun.tools.javac.parser.Scanner;
-
-public class CommentCollectingScanner extends Scanner {
+public class CommentCollectingScanner extends DocCommentScanner {
private final ListBuffer<CommentInfo> comments = ListBuffer.lb();
private int endComment = 0;
@@ -55,6 +55,7 @@ public class CommentCollectingScanner extends Scanner {
CommentInfo comment = new CommentInfo(prevEndPos, pos, endPos, content, start, end);
comments.append(comment);
+ super.processComment(style);
}
private EndConnection determineEndConnection(int pos) {
diff --git a/src/utils/lombok/javac/java7/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java7/CommentCollectingScannerFactory.java
index 9a29528e..626d3d63 100644
--- a/src/utils/lombok/javac/java7/CommentCollectingScannerFactory.java
+++ b/src/utils/lombok/javac/java7/CommentCollectingScannerFactory.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
@@ -29,17 +29,41 @@ import com.sun.tools.javac.util.Context;
public class CommentCollectingScannerFactory extends ScannerFactory {
+ @SuppressWarnings("all")
public static void preRegister(final Context context) {
if (context.get(scannerFactoryKey) == null) {
- context.put(scannerFactoryKey, new Context.Factory<ScannerFactory>() {
- public ScannerFactory make() {
+ // Careful! There is voodoo magic here!
+ //
+ // Context.Factory is parameterized. make() is for javac6 and below; make(Context) is for javac7 and up.
+ // this anonymous inner class definition is intentionally 'raw' - the return type of both 'make' methods is 'T',
+ // which means the compiler will only generate the correct "real" override method (with returntype Object, which is
+ // the lower bound for T, as a synthetic accessor for the make with returntype ScannerFactory) for that make method which
+ // is actually on the classpath (either make() for javac6-, or make(Context) for javac7+).
+ //
+ // We normally solve this issue via src/stubs, with BOTH make methods listed, but for some reason the presence of a stubbed out
+ // Context (or even a complete copy, it doesn't matter) results in a really strange eclipse bug, where any mention of any kind
+ // of com.sun.tools.javac.tree.TreeMaker in a source file disables ALL usage of 'go to declaration' and auto-complete in the entire
+ // source file.
+ //
+ // Thus, in short:
+ // * Do NOT parameterize the anonymous inner class literal.
+ // * Leave the return types as 'j.l.Object'.
+ // * Leave both make methods intact; deleting one has no effect on javac6- / javac7+, but breaks the other. Hard to test for.
+ // * Do not stub com.sun.tools.javac.util.Context or any of its inner types, like Factory.
+ @SuppressWarnings("all")
+ class MyFactory implements Context.Factory {
+ // This overrides the javac6- version of make.
+ public Object make() {
return new CommentCollectingScannerFactory(context);
}
- @Override public ScannerFactory make(Context c) {
+ // This overrides the javac7+ version.
+ public Object make(Context c) {
return new CommentCollectingScannerFactory(c);
}
- });
+ }
+ @SuppressWarnings("unchecked") Context.Factory<ScannerFactory> factory = new MyFactory();
+ context.put(scannerFactoryKey, factory);
}
}