Some work on actually making lombok work on JDK8's javac.

This commit is contained in:
Reinier Zwitserloot committed 2013-07-28 07:16:12 +02:00
1 parent 4dbe3802fd
commit d0d2dd6f5d
5 files changed
+184 -122

No files matched your search

+1 -1
View File
@@ -375,7 +375,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
if (pos == null) pos = astObject.pos();
}
if (pos != null && attemptToRemoveErrorsInRange) {
removeFromDeferredDiagnostics(pos.getStartPosition(), pos.getEndPosition(top.endPositions));
removeFromDeferredDiagnostics(pos.getStartPosition(), node.getEndPosition(pos));
}
try {
switch (kind) {
+9
View File
@@ -51,6 +51,15 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre
super(ast, node, children, kind);
}
public int getEndPosition(DiagnosticPosition pos) {
JCCompilationUnit cu = (JCCompilationUnit) top().get();
return Javac.getEndPosition(pos, cu);
}
public int getEndPosition() {
return getEndPosition(node);
}
/**
* Visits this node and all child nodes depth-first, calling the provided visitor's visit methods.
*/
@@ -44,6 +44,7 @@ import lombok.core.AnnotationValues.AnnotationValue;
import lombok.core.TransformationsUtil;
import lombok.core.TypeResolver;
import lombok.experimental.Accessors;
import lombok.javac.Javac;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
@@ -1275,17 +1276,20 @@ public class JavacHandlerUtil {
*
* in 'SETTER' mode, stripping works similarly to 'GETTER' mode, except {@code param} are copied and stripped from the original and {@code @return} are skipped.
*/
@SuppressWarnings("unchecked")
public static void copyJavadoc(JavacNode from, JCTree to, CopyJavadoc copyMode) {
if (copyMode == null) copyMode = CopyJavadoc.VERBATIM;
try {
JCCompilationUnit cu = ((JCCompilationUnit) from.top().get());
if (cu.docComments != null) {
String javadoc = cu.docComments.get(from.get());
Object dc = Javac.getDocComments(cu);
if (dc instanceof Map) {
Map<JCTree, String> docComments = (Map<JCTree, String>) dc;
String javadoc = docComments.get(from.get());
if (javadoc != null) {
String[] filtered = copyMode.split(javadoc);
cu.docComments.put(to, filtered[0]);
cu.docComments.put(from.get(), filtered[1]);
docComments.put(to, filtered[0]);
docComments.put(from.get(), filtered[1]);
}
}
} catch (Exception ignore) {}
@@ -131,12 +131,12 @@ public class PrettyCommentsPrinter extends JCTree.Visitor {
private static final TreeTag IMPORT = treeTag("IMPORT");
private static final TreeTag VARDEF = treeTag("VARDEF");
private static final TreeTag SELECT = treeTag("SELECT");
private static final Map<TreeTag, String> OPERATORS;
static {
Map<TreeTag, String> map = new HashMap<TreeTag, String>();
Map<TreeTag, String> map = new HashMap<TreeTag, String>();
map.put(treeTag("POS"), "+");
map.put(treeTag("NEG"), "-");
map.put(treeTag("NOT"), "!");
@@ -165,132 +165,133 @@ public class PrettyCommentsPrinter extends JCTree.Visitor {
map.put(treeTag("MUL"), "*");
map.put(treeTag("DIV"), "/");
map.put(treeTag("MOD"), "%");
OPERATORS = map;
OPERATORS = map;
}
private List<CommentInfo> comments;
private final JCCompilationUnit cu;
private boolean onNewLine = true;
private boolean aligned = false;
private boolean inParams = false;
private boolean needsSpace = false;
private boolean needsNewLine = false;
private boolean needsAlign = false;
private List<CommentInfo> comments;
private final JCCompilationUnit cu;
private boolean onNewLine = true;
private boolean aligned = false;
private boolean inParams = false;
private boolean needsSpace = false;
private boolean needsNewLine = false;
private boolean needsAlign = false;
public PrettyCommentsPrinter(Writer out, JCCompilationUnit cu, List<CommentInfo> comments) {
this.out = out;
this.comments = comments;
this.cu = cu;
this.comments = comments;
this.cu = cu;
}
private int endPos(JCTree tree) {
return getEndPosition(tree, cu);
}
private void consumeComments(int until) throws IOException {
consumeComments(until, null);
}
private int endPos(JCTree tree) {
return tree.getEndPosition(cu.endPositions);
}
private void consumeComments(int until) throws IOException {
consumeComments(until, null);
}
private void consumeComments(int until, JCTree tree) throws IOException {
boolean prevNewLine = onNewLine;
boolean found = false;
CommentInfo head = comments.head;
while (comments.nonEmpty() && head.pos < until) {
if (tree != null && docComments != null && docComments.containsKey(tree) && head.isJavadoc() && noFurtherJavadocForthcoming(until)) {
// This is (presumably) the exact same javadoc that has already been associated with the node that we're just about to
// print. These javadoc can be modified by lombok handlers, and as such we should NOT print them from the consumed comments db,
// and instead print the actual javadoc associated with the upcoming node (which the visit method for that node will take care of).
} else {
printComment(head);
}
comments = comments.tail;
head = comments.head;
}
if (!onNewLine && prevNewLine) {
println();
}
}
boolean prevNewLine = onNewLine;
boolean found = false;
CommentInfo head = comments.head;
while (comments.nonEmpty() && head.pos < until) {
if (tree != null && docComments != null && docComments.containsKey(tree) && head.isJavadoc() && noFurtherJavadocForthcoming(until)) {
// This is (presumably) the exact same javadoc that has already been associated with the node that we're just about to
// print. These javadoc can be modified by lombok handlers, and as such we should NOT print them from the consumed comments db,
// and instead print the actual javadoc associated with the upcoming node (which the visit method for that node will take care of).
} else {
printComment(head);
}
comments = comments.tail;
head = comments.head;
}
if (!onNewLine && prevNewLine) {
println();
}
}
private boolean noFurtherJavadocForthcoming(int until) {
List<CommentInfo> c = comments;
if (c.nonEmpty()) c = c.tail;
while (c.nonEmpty()) {
if (c.head.pos >= until) return true;
if (c.head.isJavadoc()) return false;
c = c.tail;
}
return true;
List<CommentInfo> c = comments;
if (c.nonEmpty()) c = c.tail;
while (c.nonEmpty()) {
if (c.head.pos >= until) return true;
if (c.head.isJavadoc()) return false;
c = c.tail;
}
return true;
}
private void consumeTrailingComments(int from) throws IOException {
boolean prevNewLine = onNewLine;
CommentInfo head = comments.head;
boolean stop = false;
while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) {
from = head.endPos;
printComment(head);
stop = (head.end == EndConnection.ON_NEXT_LINE);
comments = comments.tail;
head = comments.head;
}
if (!onNewLine && prevNewLine) {
println();
}
}
private void printComment(CommentInfo comment) throws IOException {
prepareComment(comment.start);
print(comment.content);
switch (comment.end) {
case ON_NEXT_LINE:
if (!aligned) {
needsNewLine = true;
needsAlign = true;
}
break;
case AFTER_COMMENT:
needsSpace = true;
break;
case DIRECT_AFTER_COMMENT:
// do nothing
break;
}
boolean prevNewLine = onNewLine;
CommentInfo head = comments.head;
boolean stop = false;
while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) {
from = head.endPos;
printComment(head);
stop = (head.end == EndConnection.ON_NEXT_LINE);
comments = comments.tail;
head = comments.head;
}
if (!onNewLine && prevNewLine) {
println();
}
}
private void printComment(CommentInfo comment) throws IOException {
prepareComment(comment.start);
print(comment.content);
switch (comment.end) {
case ON_NEXT_LINE:
if (!aligned) {
needsNewLine = true;
needsAlign = true;
}
break;
case AFTER_COMMENT:
needsSpace = true;
break;
case DIRECT_AFTER_COMMENT:
// do nothing
break;
}
}
private void prepareComment(StartConnection start) throws IOException {
switch (start) {
case DIRECT_AFTER_PREVIOUS:
needsSpace = false;
break;
case AFTER_PREVIOUS:
needsSpace = true;
break;
case START_OF_LINE:
needsNewLine = true;
needsAlign = false;
break;
case ON_NEXT_LINE:
if (!aligned) {
needsNewLine = true;
needsAlign = true;
}
break;
}
}
private void prepareComment(StartConnection start) throws IOException {
switch (start) {
case DIRECT_AFTER_PREVIOUS:
needsSpace = false;
break;
case AFTER_PREVIOUS:
needsSpace = true;
break;
case START_OF_LINE:
needsNewLine = true;
needsAlign = false;
break;
case ON_NEXT_LINE:
if (!aligned) {
needsNewLine = true;
needsAlign = true;
}
break;
}
}
/** The output stream on which trees are printed.
*/
Writer out;
/** The current left margin.
*/
int lmargin = 0;
/** The enclosing class name.
*/
Name enclClassName;
/** A hashtable mapping trees to their documentation comments
* (can be null)
*/
@@ -304,19 +305,19 @@ public class PrettyCommentsPrinter extends JCTree.Visitor {
needsAlign = false;
for (int i = 0; i < lmargin; i++) out.write("\t");
}
/** Increase left margin by indentation width.
*/
void indent() {
lmargin++;
}
/** Decrease left margin by indentation width.
*/
void undent() {
lmargin--;
}
/** Enter a new precedence level. Emit a `(' if new precedence level
* is less than precedence level so far.
* @param contextPrec The precedence level in force so far.
@@ -325,7 +326,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor {
void open(int contextPrec, int ownPrec) throws IOException {
if (ownPrec < contextPrec) out.write("(");
}
/** Leave precedence level. Emit a `(' if inner precedence level
* is less than precedence level we revert to.
* @param contextPrec The precedence level we revert to.
@@ -334,7 +335,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor {
void close(int contextPrec, int ownPrec) throws IOException {
if (ownPrec < contextPrec) out.write(")");
}
/** Print string, replacing all non-ascii character with unicode escapes.
*/
public void print(Object s) throws IOException {
+53 -5
View File
@@ -116,6 +116,18 @@ public class JavacTreeMaker {
this.paramTypes = types;
this.returnType = returnType;
}
@Override public String toString() {
StringBuilder out = new StringBuilder();
out.append(returnType.getName()).append(" ").append(owner.getName()).append(".").append(name).append("(");
boolean f = true;
for (Class<?> p : paramTypes) {
if (f) f = false;
else out.append(", ");
out.append(p.getName());
}
return out.append(")").toString();
}
}
private static class SchroedingerType {
@@ -154,13 +166,23 @@ public class JavacTreeMaker {
return value;
}
static Object getFieldCached(ConcurrentMap<Class<?>, Field> cache, Object ref, String fieldName) {
private static Field NOSUCHFIELDEX_MARKER;
static {
try {
NOSUCHFIELDEX_MARKER = SchroedingerType.class.getDeclaredField("NOSUCHFIELDEX_MARKER");
} catch (NoSuchFieldException e) {
throw Javac.sneakyThrow(e);
}
}
static Object getFieldCached(ConcurrentMap<Class<?>, Field> cache, Object ref, String fieldName) throws NoSuchFieldException {
Class<?> c = ref.getClass();
Field field = cache.get(c);
if (field == null) {
try {
field = c.getField(fieldName);
} catch (NoSuchFieldException e) {
cache.putIfAbsent(c, NOSUCHFIELDEX_MARKER);
throw Javac.sneakyThrow(e);
}
field.setAccessible(true);
@@ -168,6 +190,7 @@ public class JavacTreeMaker {
if (old != null) field = old;
}
if (field == NOSUCHFIELDEX_MARKER) throw new NoSuchFieldException(fieldName);
try {
return field.get(ref);
} catch (IllegalAccessException e) {
@@ -179,17 +202,42 @@ public class JavacTreeMaker {
public static class TypeTag extends SchroedingerType {
private static final ConcurrentMap<String, Object> TYPE_TAG_CACHE = new ConcurrentHashMap<String, Object>();
private static final ConcurrentMap<Class<?>, Field> FIELD_CACHE = new ConcurrentHashMap<Class<?>, Field>();
private static final Method TYPE_TYPETAG_METHOD;
static {
Method m = null;
try {
m = Type.class.getDeclaredMethod("getTag");
m.setAccessible(true);
} catch (NoSuchMethodException e) {}
TYPE_TYPETAG_METHOD = m;
}
private TypeTag(Object value) {
super(value);
}
public static TypeTag typeTag(JCTree o) {
return new TypeTag(getFieldCached(FIELD_CACHE, o, "typetag"));
try {
return new TypeTag(getFieldCached(FIELD_CACHE, o, "typetag"));
} catch (NoSuchFieldException e) {
throw Javac.sneakyThrow(e);
}
}
public static TypeTag typeTag(Type t) {
return new TypeTag(getFieldCached(FIELD_CACHE, t, "tag"));
try {
return new TypeTag(getFieldCached(FIELD_CACHE, t, "tag"));
} catch (NoSuchFieldException e) {
if (TYPE_TYPETAG_METHOD == null) throw new IllegalStateException("Type " + t.getClass() + " has neither 'tag' nor getTag()");
try {
return new TypeTag(TYPE_TYPETAG_METHOD.invoke(t));
} catch (IllegalAccessException ex) {
throw Javac.sneakyThrow(ex);
} catch (InvocationTargetException ex) {
throw Javac.sneakyThrow(ex.getCause());
}
}
}
public static TypeTag typeTag(String identifier) {
@@ -331,7 +379,7 @@ public class JavacTreeMaker {
if (found == null) found = method;
else throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m);
}
if (found == null) throw new IllegalStateException("Lombok TreeMaker frontedn issue: no match when looking for method: " + m);
if (found == null) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m);
found.setAccessible(true);
Object marker = METHOD_CACHE.putIfAbsent(m, found);
if (marker == null) return found;
@@ -496,7 +544,7 @@ public class JavacTreeMaker {
//javac versions: 6-8
private static final MethodId<JCThrow> Throw = MethodId("Throw");
public JCThrow Throw(JCTree expr) {
public JCThrow Throw(JCExpression expr) {
return invoke(Throw, expr);
}