diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 756b859f..3a92d205 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,6 +2,7 @@ Lombok Changelog ---------------- ### v1.18.39 "Edgy Guinea Pig" +* BUGFIX: Recent versions of eclipse (or the eclipse-based java lang server for VSCode) caused `java.lang.IllegalArgumentException: Document does not match the AST`. [Issue #3886](https://github.com/projectlombok/lombok/issues/3886). * FEATURE: `@Jacksonized @Accessors(fluent=true)` automatically creates the relevant annotations such that Jackson correctly identifies fluent accessors. * IMPROBABLE BREAKING CHANGE: From versions 1.18.16 to 1.18.38, lombok automatically copies certain Jackson annotations (e.g., `@JsonProperty`) from fields to the corresponding accessors (getters/setters). However, it turned out to be harmful in certain situations. Thus, Lombok does not automatically copy those annotations any more. You can restore the old behavior using the [config key](https://projectlombok.org/features/configuration) `lombok.copyJacksonAnnotationsToAccessors = true`. diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 954c0f39..201be4a8 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -332,8 +332,8 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .requestExtra(StackRequest.PARAM1) .transplant() .build()); - - sm.addScriptIfWitness(new String [] {"org/eclipse/jdt/internal/compiler/parser/TerminalToken"}, ScriptBuilder.replaceMethodCall() + + sm.addScriptIfComplexWitness(new String[][] {OSGI_TYPES, new String[] {"org/eclipse/jdt/internal/compiler/parser/TerminalToken"}}, ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer", "visit")) .methodToReplace(new Hook("org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner", "getTokenEndOffset", "int", "org.eclipse.jdt.internal.compiler.parser.TerminalToken", "int")) .replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getTokenEndOffsetFixed", "int", "org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner", "java.lang.Object", "int", "java.lang.Object")) diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index fa3f7edb..673186c0 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -483,7 +483,7 @@ final class PatchFixesHider { } return result; } - + public static boolean isGenerated(org.eclipse.jdt.internal.compiler.ast.ASTNode node) { boolean result = false; try { @@ -493,7 +493,7 @@ final class PatchFixesHider { } return result; } - + public static boolean isGenerated(org.eclipse.jdt.core.IMember member) { boolean result = false; try { @@ -783,6 +783,7 @@ final class PatchFixesHider { return newChildren.toArray(new RewriteEvent[0]); } + // Eclipse changed a method. Older versions have `getTokenOffset(int, int)` whereas newer ones have `getTokenOffset(TerminalToken, int)`. See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3303 public static int getTokenEndOffsetFixed(TokenScanner scanner, int token, int startOffset, Object domNode) throws CoreException { boolean isGenerated = false; try { @@ -791,18 +792,19 @@ final class PatchFixesHider { // If this fails, better to break some refactor scripts than to crash eclipse. } if (isGenerated) return -1; - - Object res = -1; + + // `scanner.getTokenEndOffset(int, int)` is public so we can just call it directly, except it might not exist (in more recent versions of eclipse). + // Ordinarily that means you just write a private static class and shove the code in there to avoid classloader errors, but we're in PatchFixes and we need to be careful about that sort of thing. try { Method m = Permit.getMethod(TokenScanner.class, "getTokenEndOffset", int.class, int.class); - res = Permit.invoke(m, scanner, token, startOffset); + return (Integer) Permit.invoke(m, scanner, token, startOffset); } catch (Exception e) { - e.printStackTrace(); - // continue + // This is bizarre; we replaced a call to this exact method which strongly suggests it should be there. It's not going to be a nice experience in eclipse to 'break' token offsets, + // but breaking token offsets is less dire than just hard crashing the entire editor with an exception. + return -1; } - return (Integer) res; } - + public static int getTokenEndOffsetFixed(TokenScanner scanner, Object token, int startOffset, Object domNode) throws CoreException { boolean isGenerated = false; try { @@ -811,18 +813,16 @@ final class PatchFixesHider { // If this fails, better to break some refactor scripts than to crash eclipse. } if (isGenerated) return -1; - - Object res = -1; + try { - // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3303 - Class TERMINAL_TOKEN_CLASS = Class.forName("org.eclipse.jdt.internal.compiler.parser.TerminalToken"); - Method m = Permit.getMethod(TokenScanner.class, "getTokenEndOffset", TERMINAL_TOKEN_CLASS, int.class); - res = Permit.invoke(m, scanner, token, startOffset); + Class terminalTokenClass = Class.forName("org.eclipse.jdt.internal.compiler.parser.TerminalToken"); + Method m = Permit.getMethod(TokenScanner.class, "getTokenEndOffset", terminalTokenClass, int.class); + return (Integer) Permit.invoke(m, scanner, token, startOffset); } catch (Exception e) { - e.printStackTrace(); - // continue + // This is bizarre; we replaced a call to this exact method which strongly suggests it should be there. It's not going to be a nice experience in eclipse to 'break' token offsets, + // but breaking token offsets is less dire than just hard crashing the entire editor with an exception. + return -1; } - return (Integer) res; } public static IMethod[] removeGeneratedMethods(IMethod[] methods) throws Exception {