diff options
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/lombok/core/FieldAugment.java | 53 | ||||
-rw-r--r-- | src/utils/lombok/eclipse/Eclipse.java | 27 | ||||
-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 | ||||
-rw-r--r-- | src/utils/lombok/permit/Permit.java | 190 | ||||
-rw-r--r-- | src/utils/lombok/permit/dummy/Child.java | 9 | ||||
-rw-r--r-- | src/utils/lombok/permit/dummy/GrandChild.java | 19 | ||||
-rw-r--r-- | src/utils/lombok/permit/dummy/Parent.java | 12 | ||||
-rw-r--r-- | src/utils/lombok/permit/dummy/package-info.java | 8 |
11 files changed, 499 insertions, 49 deletions
diff --git a/src/utils/lombok/core/FieldAugment.java b/src/utils/lombok/core/FieldAugment.java index 4a32ad04..0982bcb5 100644 --- a/src/utils/lombok/core/FieldAugment.java +++ b/src/utils/lombok/core/FieldAugment.java @@ -24,6 +24,7 @@ package lombok.core; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; @@ -69,6 +70,10 @@ public abstract class FieldAugment<T, F> { checkNotNull(fieldType, "fieldType"); checkNotNull(name, "name"); + if (type.isInterface()) { + return new InterfaceFieldAugment<T, F>(name, fieldType); + } + @SuppressWarnings("unchecked") F defaultValue = (F) getDefaultValue(fieldType); FieldAugment<T, F> ret = tryCreateReflectionAugment(type, fieldType, name, defaultValue); @@ -175,6 +180,54 @@ public abstract class FieldAugment<T, F> { */ public abstract F compareAndSet(T object, F expected, F value); + private static final class InterfaceFieldAugment<T, F> extends FieldAugment<T, F> { + private final String name; + private final Class<? super F> fieldType; + + private Map<Class<T>, FieldAugment<T, F>> map = new HashMap<Class<T>, FieldAugment<T,F>>(); + + private InterfaceFieldAugment(String name, Class<? super F> fieldType) { + this.name = name; + this.fieldType = fieldType; + } + + private synchronized FieldAugment<T, F> getDelegate(T object) { + @SuppressWarnings("unchecked") + Class<T> c = (Class<T>) object.getClass(); + + FieldAugment<T,F> fieldAugment = map.get(c); + if (fieldAugment == null) { + fieldAugment = augment(c, fieldType, name); + map.put(c, fieldAugment); + } + return fieldAugment; + } + + @Override public F get(T object) { + return getDelegate(object).get(object); + } + + @Override public F getAndSet(T object, F value) { + return getDelegate(object).getAndSet(object, value); + } + + @Override public F clear(T object) { + return getDelegate(object).clear(object); + } + + @Override public F compareAndClear(T object, F expected) { + return getDelegate(object).compareAndClear(object, expected); + } + + @Override public F setIfAbsent(T object, F value) { + return getDelegate(object).setIfAbsent(object, value); + } + + @Override public F compareAndSet(T object, F expected, F value) { + return getDelegate(object).compareAndSet(object, expected, value); + } + } + private static class ReflectionFieldAugment<T, F> extends FieldAugment<T, F> { private final Object lock = new Object(); private final Field field; diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index cda75da5..ac15f90b 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2019 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -60,6 +60,11 @@ public class Eclipse { */ public static final int ECLIPSE_DO_NOT_TOUCH_FLAG = ASTNode.Bit24; + /* This section includes flags that would ordinarily be in ClassFileConstants, but which are 'too new' (we don't compile against older versions of ecj/eclipse for compatibility). */ + public static final int AccRecord = ASTNode.Bit25; + public static final int IsCanonicalConstructor = ASTNode.Bit10; // For record declarations, and presumably later on any constructor matching the destructor. + public static final int IsImplicit = ASTNode.Bit11; // the generated statements in the compact constructor of a record. + private static final Pattern SPLIT_AT_DOT = Pattern.compile("\\."); private Eclipse() { @@ -239,18 +244,14 @@ public class Eclipse { for (Field f : CompilerOptions.class.getDeclaredFields()) { try { - if (f.getName().startsWith("VERSION_")) { - String version = f.getName().substring("VERSION_".length()); - Integer versionNumber = null; - if (version.startsWith("1_")) { - versionNumber = Integer.parseInt(version.substring("1_".length())); - } else if (version.length() <= 2) { - versionNumber = Integer.parseInt(version); - } - if (versionNumber != null) { - ecjCompilerVersionCached = Math.max(ecjCompilerVersionCached, versionNumber); - } - } + String fName = f.getName(); + String versionNumber = null; + if (fName.startsWith("VERSION_1_")) { + versionNumber = fName.substring("VERSION_1_".length()); + } else if (fName.startsWith("VERSION_")) { + versionNumber = fName.substring("VERSION_".length()); + } else continue; + ecjCompilerVersionCached = Math.max(ecjCompilerVersionCached, Integer.parseInt(versionNumber)); } catch (Exception ignore) {} } 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); diff --git a/src/utils/lombok/permit/Permit.java b/src/utils/lombok/permit/Permit.java index 407c3922..2854706e 100644 --- a/src/utils/lombok/permit/Permit.java +++ b/src/utils/lombok/permit/Permit.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-20199 The Project Lombok Authors. + * Copyright (C) 2018-2019 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 @@ -24,8 +24,17 @@ package lombok.permit; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.URL; +import javax.tools.JavaFileManager; + +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; + +import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.util.List; @@ -113,6 +122,14 @@ public class Permit { return setAccessible(m); } + public static Method permissiveGetMethod(Class<?> c, String mName, Class<?>... parameterTypes) { + try { + return getMethod(c, mName, parameterTypes); + } catch (Exception ignore) { + return null; + } + } + public static Field getField(Class<?> c, String fName) throws NoSuchFieldException { Field f = null; Class<?> oc = c; @@ -158,4 +175,175 @@ public class Permit { return null; } } + + public static boolean isDebugReflection() { + return !"false".equals(System.getProperty("lombok.debug.reflection", "false")); + } + + public static void handleReflectionDebug(Throwable t, Throwable initError) { + if (!isDebugReflection()) return; + + System.err.println("** LOMBOK REFLECTION exception: " + t.getClass() + ": " + (t.getMessage() == null ? "(no message)" : t.getMessage())); + t.printStackTrace(System.err); + if (initError != null) { + System.err.println("*** ADDITIONALLY, exception occurred setting up reflection: "); + initError.printStackTrace(System.err); + } + } + + public static Object invoke(Method m, Object receiver, Object... args) throws IllegalAccessException, InvocationTargetException { + return invoke(null, m, receiver, args); + } + + public static Object invoke(Throwable initError, Method m, Object receiver, Object... args) throws IllegalAccessException, InvocationTargetException { + try { + return m.invoke(receiver, args); + } catch (IllegalAccessException e) { + handleReflectionDebug(e, initError); + throw e; + } catch (RuntimeException e) { + handleReflectionDebug(e, initError); + throw e; + } catch (Error e) { + handleReflectionDebug(e, initError); + throw e; + } + } + + public static Object invokeSneaky(Method m, Object receiver, Object... args) { + return invokeSneaky(null, m, receiver, args); + } + + public static Object invokeSneaky(Throwable initError, Method m, Object receiver, Object... args) { + try { + return m.invoke(receiver, args); + } catch (NoClassDefFoundError e) { + handleReflectionDebug(e, initError); + //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly + //do anything useful here. + return null; + } catch (NullPointerException e) { + handleReflectionDebug(e, initError); + //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly + //do anything useful here. + return null; + } catch (IllegalAccessException e) { + handleReflectionDebug(e, initError); + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } catch (RuntimeException e) { + handleReflectionDebug(e, initError); + throw e; + } catch (Error e) { + handleReflectionDebug(e, initError); + throw e; + } + } + + public static <T> T newInstance(Constructor<T> c, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException { + return newInstance(null, c, args); + } + + public static <T> T newInstance(Throwable initError, Constructor<T> c, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException { + try { + return c.newInstance(args); + } catch (IllegalAccessException e) { + handleReflectionDebug(e, initError); + throw e; + } catch (InstantiationException e) { + handleReflectionDebug(e, initError); + throw e; + } catch (RuntimeException e) { + handleReflectionDebug(e, initError); + throw e; + } catch (Error e) { + handleReflectionDebug(e, initError); + throw e; + } + } + + public static <T> T newInstanceSneaky(Constructor<T> c, Object... args) { + return newInstanceSneaky(null, c, args); + } + + public static <T> T newInstanceSneaky(Throwable initError, Constructor<T> c, Object... args) { + try { + return c.newInstance(args); + } catch (NoClassDefFoundError e) { + handleReflectionDebug(e, initError); + //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly + //do anything useful here. + return null; + } catch (NullPointerException e) { + handleReflectionDebug(e, initError); + //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly + //do anything useful here. + return null; + } catch (IllegalAccessException e) { + handleReflectionDebug(e, initError); + throw sneakyThrow(e); + } catch (InstantiationException e) { + handleReflectionDebug(e, initError); + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } catch (RuntimeException e) { + handleReflectionDebug(e, initError); + throw e; + } catch (Error e) { + handleReflectionDebug(e, initError); + throw e; + } + } + + public static Object get(Field f, Object receiver) throws IllegalAccessException { + try { + return f.get(receiver); + } catch (IllegalAccessException e) { + handleReflectionDebug(e, null); + throw e; + } catch (RuntimeException e) { + handleReflectionDebug(e, null); + throw e; + } catch (Error e) { + handleReflectionDebug(e, null); + throw e; + } + } + + public static void set(Field f, Object receiver, Object newValue) throws IllegalAccessException { + try { + f.set(receiver, newValue); + } catch (IllegalAccessException e) { + handleReflectionDebug(e, null); + throw e; + } catch (RuntimeException e) { + handleReflectionDebug(e, null); + throw e; + } catch (Error e) { + handleReflectionDebug(e, null); + throw e; + } + } + + public static void reportReflectionProblem(Throwable initError, String msg) { + if (!isDebugReflection()) return; + System.err.println("** LOMBOK REFLECTION issue: " + msg); + if (initError != null) { + System.err.println("*** ADDITIONALLY, exception occurred setting up reflection: "); + initError.printStackTrace(System.err); + } + } + + public static RuntimeException sneakyThrow(Throwable t) { + if (t == null) throw new NullPointerException("t"); + return Permit.<RuntimeException>sneakyThrow0(t); + } + + @SuppressWarnings("unchecked") + private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T { + throw (T)t; + } + } diff --git a/src/utils/lombok/permit/dummy/Child.java b/src/utils/lombok/permit/dummy/Child.java new file mode 100644 index 00000000..c189ee37 --- /dev/null +++ b/src/utils/lombok/permit/dummy/Child.java @@ -0,0 +1,9 @@ +package lombok.permit.dummy; + +@SuppressWarnings("all") +public abstract class Child extends Parent { + private transient volatile boolean foo; + private transient volatile Object[] bar; + private transient volatile Object baz; + +} diff --git a/src/utils/lombok/permit/dummy/GrandChild.java b/src/utils/lombok/permit/dummy/GrandChild.java new file mode 100644 index 00000000..ef182aa7 --- /dev/null +++ b/src/utils/lombok/permit/dummy/GrandChild.java @@ -0,0 +1,19 @@ +package lombok.permit.dummy; + +@SuppressWarnings("all") +public final class GrandChild extends Child { + private Class<?> a; + private int b; + private String c; + private Class<?> d; + private Class<?>[] e; + private Class<?>[] f; + private int g; + private transient String h; + private transient Object i; + private byte[] j; + private byte[] k; + private byte[] l; + private volatile Object m; + private Object n; +} diff --git a/src/utils/lombok/permit/dummy/Parent.java b/src/utils/lombok/permit/dummy/Parent.java new file mode 100644 index 00000000..33928aeb --- /dev/null +++ b/src/utils/lombok/permit/dummy/Parent.java @@ -0,0 +1,12 @@ +package lombok.permit.dummy; + +import java.io.OutputStream; + +@SuppressWarnings("all") +public class Parent { + boolean first; + static final Object staticObj = OutputStream.class; + volatile Object second; + private static volatile boolean staticSecond; + private static volatile boolean staticThird; +} diff --git a/src/utils/lombok/permit/dummy/package-info.java b/src/utils/lombok/permit/dummy/package-info.java new file mode 100644 index 00000000..87ca839a --- /dev/null +++ b/src/utils/lombok/permit/dummy/package-info.java @@ -0,0 +1,8 @@ +/** + * This package recreates the type hierarchy of {@code java.lang.reflect.AccessibleObject} and friends (such as {@code java.lang.reflect.Method}); + * its purpose is to allow us to ask {@code sun.misc.internal.Unsafe} about the exact offset of the {@code override} field of {@code AccessibleObject}; + * asking about that field directly doesn't work after jdk14, presumably because the fields of AO are expressly hidden somehow. + * + * NB: It's usually 12, on the vast majority of OS, VM, and architecture combos. + */ +package lombok.permit.dummy; |