mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 16:15:16 +00:00
Some work on actually making lombok work on JDK8's javac.
This commit is contained in:
1 parent
4dbe3802fd
commit
d0d2dd6f5d
5 files changed
+184
-122
No files matched your search
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user