diff options
Diffstat (limited to 'src/utils/lombok/javac')
-rw-r--r-- | src/utils/lombok/javac/Javac.java | 26 | ||||
-rw-r--r-- | src/utils/lombok/javac/JavacTreeMaker.java | 127 | ||||
-rw-r--r-- | src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java | 27 | ||||
-rw-r--r-- | src/utils/lombok/javac/java8/CommentCollectingTokenizer.java | 50 |
4 files changed, 195 insertions, 35 deletions
diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index cec43705..c0bda93c 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -75,6 +75,12 @@ public class Javac { private static final AtomicInteger compilerVersion = new AtomicInteger(-1); + /* This section includes flags that would ordinarily be in Flags, but which are 'too new' (we don't compile against older versions of javac for compatibility). */ + public static final long RECORD = 1L << 61; // ClassSymbols, MethodSymbols, VarSymbols (Marks types as being records, as well as the 'fields' in the compact declaration, and the canonical constructor) + public static final long COMPACT_RECORD_CONSTRUCTOR = 1L << 51; // MethodSymbols (the 'implicit' many-args constructor that records have) + public static final long UNINITIALIZED_FIELD = 1L << 51; // VarSymbols (To identify fields that the compact record constructor won't initialize) + public static final long GENERATED_MEMBER = 1L << 24; // MethodSymbols, VarSymbols (marks methods and the constructor generated in records) + /** * 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}. */ @@ -279,8 +285,20 @@ public class Javac { return null; } + /** + * Checks if the javadoc comment associated with {@code tree} has a position set. + * + * Returns true if there is no javadoc comment on the node, or it has position (position isn't -1). + */ + public static boolean validateDocComment(JCCompilationUnit cu, JCTree tree) { + Object dc = getDocComments(cu); + if (!instanceOfDocCommentTable(dc)) return true; + return JavadocOps_8.validateJavadoc(dc, tree); + } + @SuppressWarnings("unchecked") public static void setDocComment(JCCompilationUnit cu, JCTree node, String javadoc) { + if (javadoc == null) return; Object dc = getDocComments(cu); if (dc instanceof Map) { ((Map<JCTree, String>) dc).put(node, javadoc); @@ -301,6 +319,12 @@ public class Javac { return javadoc.getText(); } + public static boolean validateJavadoc(Object dc, JCTree node) { + DocCommentTable dct = (DocCommentTable) dc; + Comment javadoc = dct.getComment(node); + return javadoc == null || javadoc.getText() == null || javadoc.getSourcePos(0) >= 0; + } + static void setJavadoc(Object dc, JCTree node, String javadoc) { DocCommentTable dct = (DocCommentTable) dc; Comment newCmt = createJavadocComment(javadoc, node); @@ -314,7 +338,7 @@ public class Javac { } @Override public int getSourcePos(int index) { - return -1; + return field == null ? -1 : field.getStartPosition(); } @Override public CommentStyle getStyle() { diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java index 15a11151..30d71606 100644 --- a/src/utils/lombok/javac/JavacTreeMaker.java +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -24,6 +24,7 @@ package lombok.javac; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -106,7 +107,19 @@ public class JavacTreeMaker { return this; } - private static class MethodId<J> { + private static final class FieldId<J> { + private final Class<?> owner; + private final String name; + private final Class<J> fieldType; + + FieldId(Class<?> owner, String name, Class<J> fieldType) { + this.owner = owner; + this.name = name; + this.fieldType = fieldType; + } + } + + private static final class MethodId<J> { private final Class<?> owner; private final String name; private final Class<J> returnType; @@ -332,9 +345,79 @@ public class JavacTreeMaker { throw new InternalError("Not found: " + name); } - private static final Object METHOD_NOT_FOUND = new Object[0]; - private static final Object METHOD_MULTIPLE_FOUND = new Object[0]; + static <J> FieldId<J> FieldId(Class<?> owner, String name, Class<J> fieldType) { + return new FieldId<J>(owner, name, fieldType); + } + + private static final ConcurrentHashMap<FieldId<?>, Object> FIELD_CACHE = new ConcurrentHashMap<FieldId<?>, Object>(); + + private static boolean has(FieldId<?> f) { + Object field = FIELD_CACHE.get(f); + if (field == REFLECTIVE_ITEM_NOT_FOUND) return false; + if (field instanceof Field) return true; + + try { + return getFromCache(f) != REFLECTIVE_ITEM_NOT_FOUND; + } catch (IllegalStateException e) { + return false; + } + } + + private static <J> J get(Object owner, FieldId<J> f) { + Field field = getFromCache(f); + try { + return f.fieldType.cast(field.get(owner)); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } + + private static <J> void set(Object owner, FieldId<J> f, J val) { + Field field = getFromCache(f); + try { + field.set(owner, val); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } catch (IllegalArgumentException e) { + System.err.println("Type mismatch for: " + field); + throw e; + } + } + + private static Field getFromCache(FieldId<?> f) { + Object s = FIELD_CACHE.get(f); + if (s == null) s = addToCache(f); + if (s == REFLECTIVE_ITEM_NOT_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for field: " + f); + return (Field) s; + } + + private static Object addToCache(FieldId<?> f) { + for (Field field : f.owner.getDeclaredFields()) { + if (f.name.equals(field.getName())) { + if (!Modifier.isPublic(field.getModifiers())) field.setAccessible(true); + return FIELD_CACHE.putIfAbsent(f, field); + } + } + + return FIELD_CACHE.putIfAbsent(f, REFLECTIVE_ITEM_NOT_FOUND); + } + + private static final Object REFLECTIVE_ITEM_NOT_FOUND = new Object[0]; + private static final Object REFLECTIVE_ITEM_MULTIPLE_FOUND = new Object[0]; private static final ConcurrentHashMap<MethodId<?>, Object> METHOD_CACHE = new ConcurrentHashMap<MethodId<?>, Object>(); + + private boolean has(MethodId<?> m) { + Object method = METHOD_CACHE.get(m); + if (method == REFLECTIVE_ITEM_NOT_FOUND) return false; + if (method instanceof Method) return true; + + try { + return getFromCache(m) != REFLECTIVE_ITEM_NOT_FOUND; + } catch (IllegalStateException e) { + return false; + } + } + private <J> J invoke(MethodId<J> m, Object... args) { return invokeAny(tm, m, args); } @@ -351,8 +434,8 @@ public class JavacTreeMaker { } catch (IllegalAccessException e) { throw Javac.sneakyThrow(e); } catch (IllegalArgumentException e) { - System.err.println(method); - throw Javac.sneakyThrow(e); + System.err.println("Type mismatch for: " + method); + throw e; } } @@ -366,8 +449,8 @@ public class JavacTreeMaker { private static Method getFromCache(MethodId<?> m) { Object s = METHOD_CACHE.get(m); if (s == null) s = addToCache(m); - if (s == METHOD_MULTIPLE_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); - if (s == METHOD_NOT_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m); + if (s == REFLECTIVE_ITEM_MULTIPLE_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); + if (s == REFLECTIVE_ITEM_NOT_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m); return (Method) s; } @@ -391,13 +474,13 @@ public class JavacTreeMaker { } if (found == null) found = method; else { - METHOD_CACHE.putIfAbsent(m, METHOD_MULTIPLE_FOUND); - return METHOD_MULTIPLE_FOUND; + METHOD_CACHE.putIfAbsent(m, REFLECTIVE_ITEM_MULTIPLE_FOUND); + return REFLECTIVE_ITEM_MULTIPLE_FOUND; } } if (found == null) { - METHOD_CACHE.putIfAbsent(m, METHOD_NOT_FOUND); - return METHOD_NOT_FOUND; + METHOD_CACHE.putIfAbsent(m, REFLECTIVE_ITEM_NOT_FOUND); + return REFLECTIVE_ITEM_NOT_FOUND; } Permit.setAccessible(found); Object marker = METHOD_CACHE.putIfAbsent(m, found); @@ -431,8 +514,12 @@ public class JavacTreeMaker { //javac versions: 8 private static final MethodId<JCMethodDecl> MethodDefWithRecvParam = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, JCVariableDecl.class, List.class, List.class, JCBlock.class, JCExpression.class); - public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, JCVariableDecl recvparam, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { - return invoke(MethodDefWithRecvParam, mods, name, resType, recvparam, typarams, params, thrown, body, defaultValue); + public boolean hasMethodDefWithRecvParam() { + return has(MethodDefWithRecvParam); + } + + public JCMethodDecl MethodDefWithRecvParam(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, JCVariableDecl recvparam, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDefWithRecvParam, mods, name, resType, typarams, recvparam, params, thrown, body, defaultValue); } //javac versions: 6-8 @@ -878,4 +965,18 @@ public class JavacTreeMaker { public JCExpression Type(Type type) { return invoke(Type, type); } + + private static final FieldId<JCVariableDecl> MethodDecl_recvParam = FieldId(JCMethodDecl.class, "recvparam", JCVariableDecl.class); + //javac versions: 8+ + public boolean hasReceiverParameter() { + return has(MethodDecl_recvParam); + } + + public JCVariableDecl getReceiverParameter(JCMethodDecl method) { + return get(method, MethodDecl_recvParam); + } + + public void setReceiverParameter(JCMethodDecl method, JCVariableDecl param) { + set(method, MethodDecl_recvParam, param); + } }
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java index cb0d2e12..f29f501b 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java +++ b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2019 The Project Lombok Authors. + * Copyright (C) 2011-2021 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 @@ -72,18 +72,31 @@ public class CommentCollectingScannerFactory extends ScannerFactory { super(context); } + @SuppressWarnings("all") @Override public Scanner newScanner(CharSequence input, boolean keepDocComments) { - if (input instanceof CharBuffer) { - CharBuffer buf = (CharBuffer) input; - return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, buf, findTextBlocks)); + char[] array; + int limit; + if (input instanceof CharBuffer && ((CharBuffer) input).hasArray()) { + CharBuffer cb = (CharBuffer) input; + cb.compact().flip(); + array = cb.array(); + limit = cb.limit(); + } else { + array = input.toString().toCharArray(); + limit = array.length; + } + if (array.length == limit) { + // work around a bug where the last comment in a file falls away in this case. + char[] d = new char[limit + 1]; + System.arraycopy(array, 0, d, 0, limit); + array = d; } - char[] array = input.toString().toCharArray(); - return newScanner(array, array.length, keepDocComments); + return newScanner(array, limit, keepDocComments); } @Override public Scanner newScanner(char[] input, int inputLength, boolean keepDocComments) { - return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, input, inputLength, findTextBlocks)); + return new CommentCollectingScanner(this, CommentCollectingTokenizer.create(this, input, inputLength, findTextBlocks)); } } diff --git a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java index d7b1d569..4a31fc81 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java +++ b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-2021 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 @@ -23,36 +23,51 @@ package lombok.javac.java8; import java.nio.CharBuffer; -import lombok.javac.CommentInfo; -import lombok.javac.CommentInfo.EndConnection; -import lombok.javac.CommentInfo.StartConnection; - import com.sun.tools.javac.parser.JavaTokenizer; import com.sun.tools.javac.parser.ScannerFactory; import com.sun.tools.javac.parser.Tokens.Comment; -import com.sun.tools.javac.parser.Tokens.Token; import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; +import com.sun.tools.javac.parser.Tokens.Token; import com.sun.tools.javac.parser.UnicodeReader; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; +import lombok.javac.CommentInfo; +import lombok.javac.CommentInfo.EndConnection; +import lombok.javac.CommentInfo.StartConnection; + class CommentCollectingTokenizer extends JavaTokenizer { + + private static final boolean tokenizerIsUnicodeReader = JavaTokenizer.class.getSuperclass().getSimpleName().equals("UnicodeReader"); + private int prevEndPosition = 0; private final ListBuffer<CommentInfo> comments = new ListBuffer<CommentInfo>(); private final ListBuffer<Integer> textBlockStarts; private int endComment = 0; - CommentCollectingTokenizer(ScannerFactory fac, char[] buf, int inputLength, boolean findTextBlocks) { + static CommentCollectingTokenizer create(ScannerFactory fac, char[] buf, int inputLength, boolean findTextBlocks) { + if (tokenizerIsUnicodeReader) { + return new CommentCollectingTokenizer(fac, buf, inputLength, findTextBlocks, true); + } + return new CommentCollectingTokenizer(fac, buf, inputLength, findTextBlocks); + } + + // pre java 16 + private CommentCollectingTokenizer(ScannerFactory fac, char[] buf, int inputLength, boolean findTextBlocks) { super(fac, new PositionUnicodeReader(fac, buf, inputLength)); textBlockStarts = findTextBlocks ? new ListBuffer<Integer>() : null; } - CommentCollectingTokenizer(ScannerFactory fac, CharBuffer buf, boolean findTextBlocks) { - super(fac, new PositionUnicodeReader(fac, buf)); + // from java 16 + private CommentCollectingTokenizer(ScannerFactory fac, char[] buf, int inputLength, boolean findTextBlocks, boolean java16Signature) { + super(fac, buf, inputLength); textBlockStarts = findTextBlocks ? new ListBuffer<Integer>() : null; } int pos() { + if (tokenizerIsUnicodeReader) { + return position(); + } return ((PositionUnicodeReader) reader).pos(); } @@ -60,8 +75,8 @@ class CommentCollectingTokenizer extends JavaTokenizer { Token token = super.readToken(); prevEndPosition = pos(); if (textBlockStarts != null && (prevEndPosition - token.pos > 5) && token.getClass().getName().endsWith("$StringToken")) { - char[] start = reader.getRawCharacters(token.pos, token.pos + 3); - if (start[0] == '"' && start[1] == '"' && start[2] == '"') textBlockStarts.add(token.pos); + char[] start = reader().getRawCharacters(token.pos, token.pos + 3); + if (start[0] == '"' && start[1] == '"' && start[2] == '"') textBlockStarts.append(token.pos); } return token; } @@ -70,7 +85,7 @@ class CommentCollectingTokenizer extends JavaTokenizer { protected Comment processComment(int pos, int endPos, CommentStyle style) { int prevEndPos = Math.max(prevEndPosition, endComment); endComment = endPos; - String content = new String(reader.getRawCharacters(pos, endPos)); + String content = new String(reader().getRawCharacters(pos, endPos)); StartConnection start = determineStartConnection(prevEndPos, pos); EndConnection end = determineEndConnection(endPos); @@ -85,7 +100,7 @@ class CommentCollectingTokenizer extends JavaTokenizer { for (int i = pos;; i++) { char c; try { - c = reader.getRawCharacters(i, i + 1)[0]; + c = reader().getRawCharacters(i, i + 1)[0]; } catch (IndexOutOfBoundsException e) { c = '\n'; } @@ -104,7 +119,7 @@ class CommentCollectingTokenizer extends JavaTokenizer { if (from == to) { return StartConnection.DIRECT_AFTER_PREVIOUS; } - char[] between = reader.getRawCharacters(from, to); + char[] between = reader().getRawCharacters(from, to); if (isNewLine(between[between.length - 1])) { return StartConnection.START_OF_LINE; } @@ -128,6 +143,13 @@ class CommentCollectingTokenizer extends JavaTokenizer { return textBlockStarts == null ? List.<Integer>nil() : textBlockStarts.toList(); } + private UnicodeReader reader() { + if (tokenizerIsUnicodeReader) { + return (UnicodeReader) (Object) this; + } + return reader; + } + static class PositionUnicodeReader extends UnicodeReader { protected PositionUnicodeReader(ScannerFactory sf, char[] input, int inputLength) { super(sf, input, inputLength); |