diff options
Diffstat (limited to 'src/eclipseAgent/lombok')
12 files changed, 1263 insertions, 543 deletions
diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcher.java new file mode 100644 index 00000000..aa01c13d --- /dev/null +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcher.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.agent; + +import lombok.patcher.ClassRootFinder; +import lombok.patcher.Hook; +import lombok.patcher.MethodTarget; +import lombok.patcher.ScriptManager; +import lombok.patcher.StackRequest; +import lombok.patcher.scripts.ScriptBuilder; + +public class EclipseLoaderPatcher { + private static final String TRANSPLANTS_CLASS_NAME = "lombok.eclipse.agent.EclipseLoaderPatcherTransplants"; + + public static void patchEquinoxLoaders(ScriptManager sm, Class<?> launchingContext) { + sm.addScript(ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader", "loadClass", + "java.lang.Class", "java.lang.String", "boolean")) + .target(new MethodTarget("org.eclipse.osgi.framework.adapter.core.AbstractClassLoader", "loadClass", + "java.lang.Class", "java.lang.String", "boolean")) + .target(new MethodTarget("org.eclipse.osgi.internal.loader.ModuleClassLoader", "loadClass", + "java.lang.Class", "java.lang.String", "boolean")) + .decisionMethod(new Hook(TRANSPLANTS_CLASS_NAME, "overrideLoadDecide", "boolean", "java.lang.ClassLoader", "java.lang.String", "boolean")) + .valueMethod(new Hook(TRANSPLANTS_CLASS_NAME, "overrideLoadResult", "java.lang.Class", "java.lang.ClassLoader", "java.lang.String", "boolean")) + .transplant() + .request(StackRequest.THIS, StackRequest.PARAM1, StackRequest.PARAM2).build()); + + sm.addScript(ScriptBuilder.addField().setPublic().setVolatile() + .fieldType("Ljava/lang/ClassLoader;") + .fieldName("lombok$shadowLoader") + .targetClass("org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader") + .targetClass("org.eclipse.osgi.framework.adapter.core.AbstractClassLoader") + .targetClass("org.eclipse.osgi.internal.loader.ModuleClassLoader") + .build()); + + sm.addScript(ScriptBuilder.addField().setPublic().setVolatile().setStatic() + .fieldType("Ljava/lang/Class;") + .fieldName("lombok$shadowLoaderClass") + .targetClass("org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader") + .targetClass("org.eclipse.osgi.framework.adapter.core.AbstractClassLoader") + .targetClass("org.eclipse.osgi.internal.loader.ModuleClassLoader") + .build()); + + sm.addScript(ScriptBuilder.addField().setPublic().setStatic().setFinal() + .fieldType("Ljava/lang/String;") + .fieldName("lombok$location") + .targetClass("org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader") + .targetClass("org.eclipse.osgi.framework.adapter.core.AbstractClassLoader") + .targetClass("org.eclipse.osgi.internal.loader.ModuleClassLoader") + .value(ClassRootFinder.findClassRootOfClass(launchingContext)) + .build()); + } +} diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcherTransplants.java b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcherTransplants.java new file mode 100644 index 00000000..ea72f56a --- /dev/null +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcherTransplants.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.agent; + +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +/** + * Contains all the code to be transplanted into eclipse. + * + * Do not use: + * + * * Annotations + * * Generics + * * Varargs + * * Auto (un)boxing + * * class literals + * + * The above because this code is compiled with -source 1.4, and is transplanted. + * + * NB: The suppress warnings will be stripped out before compilation. + */ +@SuppressWarnings("all") +public class EclipseLoaderPatcherTransplants { + public static boolean overrideLoadDecide(ClassLoader original, String name, boolean resolve) { + return name.startsWith("lombok."); + } + + public static Class overrideLoadResult(ClassLoader original, String name, boolean resolve) throws ClassNotFoundException { + try { + Field shadowLoaderField = original.getClass().getField("lombok$shadowLoader"); + ClassLoader shadowLoader = (ClassLoader) shadowLoaderField.get(original); + if (shadowLoader == null) { + synchronized ("lombok$shadowLoader$globalLock".intern()) { + shadowLoader = (ClassLoader) shadowLoaderField.get(original); + if (shadowLoader == null) { + Class shadowClassLoaderClass = (Class) original.getClass().getField("lombok$shadowLoaderClass").get(null); + Class classLoaderClass = Class.forName("java.lang.ClassLoader"); + String jarLoc = (String) original.getClass().getField("lombok$location").get(null); + if (shadowClassLoaderClass == null) { + JarFile jf = new JarFile(jarLoc); + InputStream in = null; + try { + ZipEntry entry = jf.getEntry("lombok/launch/ShadowClassLoader.class"); + in = jf.getInputStream(entry); + byte[] bytes = new byte[65536]; + int len = 0; + while (true) { + int r = in.read(bytes, len, bytes.length - len); + if (r == -1) break; + len += r; + if (len == bytes.length) throw new IllegalStateException("lombok.launch.ShadowClassLoader too large."); + } + in.close(); + { + Class[] paramTypes = new Class[4]; + paramTypes[0] = "".getClass(); + paramTypes[1] = new byte[0].getClass(); + paramTypes[2] = Integer.TYPE; + paramTypes[3] = paramTypes[2]; + Method defineClassMethod = classLoaderClass.getDeclaredMethod("defineClass", paramTypes); + defineClassMethod.setAccessible(true); + shadowClassLoaderClass = (Class) defineClassMethod.invoke(original, new Object[] {"lombok.launch.ShadowClassLoader", bytes, new Integer(0), new Integer(len)}); + original.getClass().getField("lombok$shadowLoaderClass").set(null, shadowClassLoaderClass); + } + } finally { + if (in != null) in.close(); + jf.close(); + } + } + Class[] paramTypes = new Class[5]; + paramTypes[0] = classLoaderClass; + paramTypes[1] = "".getClass(); + paramTypes[2] = paramTypes[1]; + paramTypes[3] = Class.forName("java.util.List"); + paramTypes[4] = paramTypes[3]; + Constructor constructor = shadowClassLoaderClass.getDeclaredConstructor(paramTypes); + constructor.setAccessible(true); + shadowLoader = (ClassLoader) constructor.newInstance(new Object[] {original, "lombok", jarLoc, Arrays.asList(new Object[] {"lombok."}), Arrays.asList(new Object[] {"lombok.patcher.Symbols"})}); + shadowLoaderField.set(original, shadowLoader); + } + } + } + + if (resolve) { + Class[] paramTypes = new Class[2]; + paramTypes[0] = "".getClass(); + paramTypes[1] = Boolean.TYPE; + Method m = shadowLoader.getClass().getDeclaredMethod("loadClass", new Class[] {String.class, boolean.class}); + m.setAccessible(true); + return (Class) m.invoke(shadowLoader, new Object[] {name, Boolean.TRUE}); + } else { + return shadowLoader.loadClass(name); + } + } catch (Exception ex) { + Throwable t = ex; + if (t instanceof InvocationTargetException) t = t.getCause(); + if (t instanceof RuntimeException) throw (RuntimeException) t; + if (t instanceof Error) throw (Error) t; + throw new RuntimeException(t); + } + } +} diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index e14d1367..a6d745b6 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2015 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,18 +23,22 @@ package lombok.eclipse.agent; import static lombok.patcher.scripts.ScriptBuilder.*; +import java.io.File; import java.lang.instrument.Instrumentation; +import java.net.URLClassLoader; +import java.security.ProtectionDomain; import java.util.Collection; import java.util.Collections; import java.util.List; -import lombok.core.Agent; +import lombok.core.AgentLauncher; +import lombok.patcher.Filter; import lombok.patcher.Hook; import lombok.patcher.MethodTarget; import lombok.patcher.ScriptManager; import lombok.patcher.StackRequest; import lombok.patcher.TargetMatcher; -import lombok.patcher.equinox.EquinoxClassLoader; +import lombok.patcher.TransplantMapper; import lombok.patcher.scripts.ScriptBuilder; /** @@ -44,13 +48,12 @@ import lombok.patcher.scripts.ScriptBuilder; * classes in this package for more information about which classes are transformed and how they are * transformed. */ -public class EclipsePatcher extends Agent { +public class EclipsePatcher implements AgentLauncher.AgentLaunchable { // At some point I'd like the agent to be capable of auto-detecting if its on eclipse or on ecj. This class is a sure sign we're not in ecj but in eclipse. -ReinierZ @SuppressWarnings("unused") private static final String ECLIPSE_SIGNATURE_CLASS = "org/eclipse/core/runtime/adaptor/EclipseStarter"; - @Override - public void runAgent(String agentArgs, Instrumentation instrumentation, boolean injected) throws Exception { + @Override public void runAgent(String agentArgs, Instrumentation instrumentation, boolean injected, Class<?> launchingContext) throws Exception { String[] args = agentArgs == null ? new String[0] : agentArgs.split(":"); boolean forceEcj = false; boolean forceEclipse = false; @@ -69,18 +72,31 @@ public class EclipsePatcher extends Agent { else if (forceEclipse) ecj = false; else ecj = injected; - registerPatchScripts(instrumentation, injected, ecj); + registerPatchScripts(instrumentation, injected, ecj, launchingContext); } - private static void registerPatchScripts(Instrumentation instrumentation, boolean reloadExistingClasses, boolean ecjOnly) { + private static void registerPatchScripts(Instrumentation instrumentation, boolean reloadExistingClasses, boolean ecjOnly, Class<?> launchingContext) { ScriptManager sm = new ScriptManager(); sm.registerTransformer(instrumentation); - if (!ecjOnly) { - EquinoxClassLoader.addPrefix("lombok."); - EquinoxClassLoader.registerScripts(sm); - } + sm.setFilter(new Filter() { + @Override public boolean shouldTransform(ClassLoader loader, String className, Class<?> classBeingDefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + if (!(loader instanceof URLClassLoader)) return true; + ClassLoader parent = loader.getParent(); + if (parent == null) return true; + return !parent.getClass().getName().startsWith("org.eclipse.jdt.apt.core.internal.AnnotationProcessorFactoryLoader"); + } + }); + + final boolean forceBaseResourceNames = shouldForceBaseResourceNames(); + sm.setTransplantMapper(new TransplantMapper() { + public String mapResourceName(int classFileFormatVersion, String resourceName) { + if (classFileFormatVersion < 50 || forceBaseResourceNames) return resourceName; + return "Class50/" + resourceName; + } + }); if (!ecjOnly) { + EclipseLoaderPatcher.patchEquinoxLoaders(sm, launchingContext); patchCatchReparse(sm); patchIdentifierEndReparse(sm); patchRetrieveEllipsisStartPosition(sm); @@ -90,7 +106,7 @@ public class EclipsePatcher extends Agent { patchHideGeneratedNodes(sm); patchPostCompileHookEclipse(sm); patchFixSourceTypeConverter(sm); - patchDisableLombokForCodeFormatterAndCleanup(sm); + patchDisableLombokForCodeCleanup(sm); patchListRewriteHandleGeneratedMethods(sm); patchSyntaxAndOccurrencesHighlighting(sm); patchSortMembersOperation(sm); @@ -105,16 +121,43 @@ public class EclipsePatcher extends Agent { patchLombokizeAST(sm); patchEcjTransformers(sm, ecjOnly); patchExtensionMethod(sm, ecjOnly); + patchRenameField(sm); if (reloadExistingClasses) sm.reloadClasses(instrumentation); } + private static boolean shouldForceBaseResourceNames() { + String shadowOverride = System.getProperty("shadow.override.lombok", ""); + if (shadowOverride == null || shadowOverride.length() == 0) return false; + for (String part : shadowOverride.split("\\s*" + (File.pathSeparatorChar == ';' ? ";" : ":") + "\\s*")) { + if (part.equalsIgnoreCase("lombok.jar")) return false; + } + return true; + } + + private static void patchRenameField(ScriptManager sm) { + /* RefactoringSearchEngine.search will not return results when renaming field and Data Annotation is present. Return a fake Element to make checks pass */ + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.rename.RenameFieldProcessor", "checkAccessorDeclarations", "org.eclipse.ltk.core.refactoring.RefactoringStatus", "org.eclipse.core.runtime.IProgressMonitor", "org.eclipse.jdt.core.IMethod")) + .methodToWrap(new Hook("org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine", "search", "org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup[]", "org.eclipse.jdt.core.search.SearchPattern","org.eclipse.jdt.core.search.IJavaSearchScope","org.eclipse.core.runtime.IProgressMonitor","org.eclipse.ltk.core.refactoring.RefactoringStatus")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "createFakeSearchResult", "org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup[]", "org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup[]", "java.lang.Object")) + .requestExtra(StackRequest.THIS) + .transplant().build()); + + /* Filter search results which are Generated and based on Fields, e.g. Generated getters/setters */ + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.rename.RenameFieldProcessor", "addAccessorOccurrences", "void", "org.eclipse.core.runtime.IProgressMonitor", "org.eclipse.jdt.core.IMethod", "java.lang.String","java.lang.String","org.eclipse.ltk.core.refactoring.RefactoringStatus")) + .methodToWrap(new Hook("org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup", "getSearchResults", "org.eclipse.jdt.core.search.SearchMatch[]")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGenerated", "org.eclipse.jdt.core.search.SearchMatch[]", "org.eclipse.jdt.core.search.SearchMatch[]")) + .transplant().build()); + } + private static void patchExtractInterface(ScriptManager sm) { /* Fix sourceEnding for generated nodes to avoid null pointer */ sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.compiler.SourceElementNotifier", "notifySourceElementRequestor", "void", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "org.eclipse.jdt.internal.compiler.ast.ImportReference")) .methodToWrap(new Hook("org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt", "get", "int", "java.lang.Object")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "getSourceEndFixed", "int", "int", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getSourceEndFixed", "int", "int", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .requestExtra(StackRequest.PARAM1) .transplant().build()); @@ -127,7 +170,7 @@ public class EclipsePatcher extends Agent { "org.eclipse.jdt.core.dom.MethodDeclaration" )) .methodToWrap(new Hook("org.eclipse.jface.text.IDocument", "get", "java.lang.String", "int", "int")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "getRealMethodDeclarationSource", "java.lang.String", "java.lang.String", "java.lang.Object", "org.eclipse.jdt.core.dom.MethodDeclaration")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealMethodDeclarationSource", "java.lang.String", "java.lang.String", "java.lang.Object", "org.eclipse.jdt.core.dom.MethodDeclaration")) .requestExtra(StackRequest.THIS, StackRequest.PARAM4) .transplant().build()); @@ -136,20 +179,20 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMemberDeclarations")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMethodComments")) .methodToReplace(new Hook("org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil", "getMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) - .replacementMethod(new Hook("lombok.eclipse.agent.PatchFixes", "getRealMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) + .replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) .transplant().build()); /* Do not add @Override's for generated methods */ sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget("org.eclipse.jdt.core.dom.rewrite.ListRewrite", "insertFirst")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isListRewriteOnGeneratedNode", "boolean", "org.eclipse.jdt.core.dom.rewrite.ListRewrite")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isListRewriteOnGeneratedNode", "boolean", "org.eclipse.jdt.core.dom.rewrite.ListRewrite")) .request(StackRequest.THIS) .transplant().build()); /* Do not add comments for generated methods */ sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMethodComment")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .request(StackRequest.PARAM2) .transplant().build()); } @@ -162,7 +205,7 @@ public class EclipsePatcher extends Agent { */ sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.core.internal.runtime.Product", "getProperty", "java.lang.String", "java.lang.String")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "addLombokNotesToEclipseAboutDialog", "java.lang.String", "java.lang.String", "java.lang.String")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$LombokDeps", "addLombokNotesToEclipseAboutDialog", "java.lang.String", "java.lang.String", "java.lang.String")) .request(StackRequest.RETURN_VALUE, StackRequest.PARAM1) .transplant().build()); } @@ -175,19 +218,13 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.internal.ui.search.OccurrencesFinder", "addUsage")) .target(new MethodTarget("org.eclipse.jdt.internal.ui.search.OccurrencesFinder", "addWrite")) .target(new MethodTarget("org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingReconciler$PositionCollector", "visit", "boolean", "org.eclipse.jdt.core.dom.SimpleName")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) - .valueMethod(new Hook("lombok.eclipse.agent.PatchFixes", "returnFalse", "boolean", "java.lang.Object")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) + .valueMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "returnFalse", "boolean", "java.lang.Object")) .request(StackRequest.PARAM1) .build()); } - private static void patchDisableLombokForCodeFormatterAndCleanup(ScriptManager sm) { - sm.addScript(ScriptBuilder.setSymbolDuringMethodCall() - .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "formatCompilationUnit")) - .callToWrap(new Hook("org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil", "parseCompilationUnit", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "char[]", "java.util.Map", "boolean")) - .symbol("lombok.disable") - .build()); - + private static void patchDisableLombokForCodeCleanup(ScriptManager sm) { sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.DoStatement")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.EnhancedForStatement")) @@ -201,9 +238,9 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.CodeStyleFix$CodeStyleVisitor", "visit", "boolean", "org.eclipse.jdt.core.dom.QualifiedName")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.CodeStyleFix$CodeStyleVisitor", "visit", "boolean", "org.eclipse.jdt.core.dom.SimpleName")) // if a generated node has children we can just ignore them as well; - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .request(StackRequest.PARAM1) - .valueMethod(new Hook("lombok.eclipse.agent.PatchFixes", "returnFalse", "boolean", "java.lang.Object")) + .valueMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "returnFalse", "boolean", "java.lang.Object")) .build()); } @@ -211,7 +248,7 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer$ListRewriter", "rewriteList")) .methodToReplace(new Hook("org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent", "getChildren", "org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent[]")) - .replacementMethod(new Hook("lombok.eclipse.agent.PatchFixes", "listRewriteHandleGeneratedMethods", "org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent[]", "org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent")) + .replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "listRewriteHandleGeneratedMethods", "org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent[]", "org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent")) .build()); } @@ -223,37 +260,37 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.SortElementsOperation$2", "visit", "boolean", "org.eclipse.jdt.core.dom.CompilationUnit")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.CompilationUnit", "types", "java.util.List")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) .transplant().build()); sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.SortElementsOperation$2", "visit", "boolean", "org.eclipse.jdt.core.dom.AnnotationTypeDeclaration")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.AnnotationTypeDeclaration", "bodyDeclarations", "java.util.List")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) .transplant().build()); sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.SortElementsOperation$2", "visit", "boolean", "org.eclipse.jdt.core.dom.AnonymousClassDeclaration")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.AnonymousClassDeclaration", "bodyDeclarations", "java.util.List")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) .transplant().build()); sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.SortElementsOperation$2", "visit", "boolean", "org.eclipse.jdt.core.dom.TypeDeclaration")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.TypeDeclaration", "bodyDeclarations", "java.util.List")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) .transplant().build()); sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.SortElementsOperation$2", "visit", "boolean", "org.eclipse.jdt.core.dom.EnumDeclaration")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.EnumDeclaration", "bodyDeclarations", "java.util.List")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) .transplant().build()); sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.SortElementsOperation$2", "visit", "boolean", "org.eclipse.jdt.core.dom.EnumDeclaration")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.EnumDeclaration", "enumConstants", "java.util.List")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedNodes", "java.util.List", "java.util.List")) .transplant().build()); } @@ -261,7 +298,7 @@ public class EclipsePatcher extends Agent { sm.addScript(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", "int", "int")) - .replacementMethod(new Hook("lombok.eclipse.agent.PatchFixes", "getTokenEndOffsetFixed", "int", "org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner", "int", "int", "java.lang.Object")) + .replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getTokenEndOffsetFixed", "int", "org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner", "int", "int", "java.lang.Object")) .requestExtra(StackRequest.PARAM1) .transplant() .build()); @@ -273,7 +310,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder", "writeClassFileContents")) .target(new MethodTarget("org.eclipse.jdt.internal.core.builder.AbstractImageBuilder", "writeClassFileContents")) .methodToWrap(new Hook("org.eclipse.jdt.internal.compiler.ClassFile", "getBytes", "byte[]")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "runPostCompiler", "byte[]", "byte[]", "java.lang.String")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$LombokDeps", "runPostCompiler", "byte[]", "byte[]", "java.lang.String")) .requestExtra(StackRequest.PARAM3) .build()); } @@ -282,24 +319,22 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.compiler.tool.EclipseCompilerImpl", "outputClassFiles")) .methodToWrap(new Hook("javax.tools.JavaFileObject", "openOutputStream", "java.io.OutputStream")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "runPostCompiler", "java.io.OutputStream", "java.io.OutputStream")) - .transplant() - .build()); + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$LombokDeps", "runPostCompiler", "java.io.OutputStream", "java.io.OutputStream")) + .transplant().build()); sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.compiler.util.Util", "writeToDisk")) .methodToWrap(new Hook("java.io.BufferedOutputStream", "<init>", "void", "java.io.OutputStream", "int")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "runPostCompiler", "java.io.BufferedOutputStream", "java.io.BufferedOutputStream", "java.lang.String", "java.lang.String")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$LombokDeps", "runPostCompiler", "java.io.BufferedOutputStream", "java.io.BufferedOutputStream", "java.lang.String", "java.lang.String")) .requestExtra(StackRequest.PARAM2, StackRequest.PARAM3) - .transplant() - .build()); + .transplant().build()); } private static void patchHideGeneratedNodes(ScriptManager sm) { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder", "findByNode")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder", "findByBinding")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedSimpleNames", "org.eclipse.jdt.core.dom.SimpleName[]", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedSimpleNames", "org.eclipse.jdt.core.dom.SimpleName[]", "org.eclipse.jdt.core.dom.SimpleName[]")) .request(StackRequest.RETURN_VALUE).build()); @@ -308,33 +343,41 @@ public class EclipsePatcher extends Agent { } private static void patchFormatters(ScriptManager sm) { + // before Eclipse Mars sm.addScript(ScriptBuilder.setSymbolDuringMethodCall() - .target(new MethodTarget("org.eclipse.jdt.internal.ui.text.java.JavaFormattingStrategy", "format", "void")) - .callToWrap(new Hook("org.eclipse.jdt.internal.corext.util.CodeFormatterUtil", "reformat", "org.eclipse.text.edits.TextEdit", - "int", "java.lang.String", "int", "int", "int", "java.lang.String", "java.util.Map")) - .symbol("lombok.disable").build()); + .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "formatCompilationUnit")) + .callToWrap(new Hook("org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil", "parseCompilationUnit", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "char[]", "java.util.Map", "boolean")) + .symbol("lombok.disable") + .build()); + + // Eclipse Mars and beyond + sm.addScript(ScriptBuilder.setSymbolDuringMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "parseSourceCode")) + .callToWrap(new Hook("org.eclipse.jdt.core.dom.ASTParser", "createAST", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.core.runtime.IProgressMonitor")) + .symbol("lombok.disable") + .build()); } private static void patchRefactorScripts(ScriptManager sm) { sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget("org.eclipse.jdt.core.dom.rewrite.ASTRewrite", "replace")) .target(new MethodTarget("org.eclipse.jdt.core.dom.rewrite.ASTRewrite", "remove")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "skipRewritingGeneratedNodes", "boolean", + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "skipRewritingGeneratedNodes", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .transplant().request(StackRequest.PARAM1).build()); sm.addScript(ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.rename.RenameTypeProcessor", "addConstructorRenames")) .methodToWrap(new Hook("org.eclipse.jdt.core.IType", "getMethods", "org.eclipse.jdt.core.IMethod[]")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "removeGeneratedMethods", "org.eclipse.jdt.core.IMethod[]", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "removeGeneratedMethods", "org.eclipse.jdt.core.IMethod[]", "org.eclipse.jdt.core.IMethod[]")) .transplant().build()); sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.rename.TempOccurrenceAnalyzer", "visit", "boolean", "org.eclipse.jdt.core.dom.SimpleName")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.rename.RenameAnalyzeUtil$ProblemNodeFinder$NameNodeVisitor", "visit", "boolean", "org.eclipse.jdt.core.dom.SimpleName")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) - .valueMethod(new Hook("lombok.eclipse.agent.PatchFixes", "returnTrue", "boolean", "java.lang.Object")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) + .valueMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "returnTrue", "boolean", "java.lang.Object")) .request(StackRequest.PARAM1) .transplant().build()); } @@ -342,30 +385,54 @@ public class EclipsePatcher extends Agent { private static void patchCatchReparse(ScriptManager sm) { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveStartingCatchPosition")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "fixRetrieveStartingCatchPosition", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveStartingCatchPosition", "int", "int", "int")) .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM1).build()); } private static void patchIdentifierEndReparse(ScriptManager sm) { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveIdentifierEndPosition")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "fixRetrieveIdentifierEndPosition", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveIdentifierEndPosition", "int", "int", "int")) .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build()); } private static void patchRetrieveEllipsisStartPosition(ScriptManager sm) { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveEllipsisStartPosition")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "fixRetrieveEllipsisStartPosition", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveEllipsisStartPosition", "int", "int", "int")) .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build()); } private static void patchRetrieveRightBraceOrSemiColonPosition(ScriptManager sm) { - sm.addScript(ScriptBuilder.wrapReturnValue() - .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveRightBraceOrSemiColonPosition")) - .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveRightBrace")) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "fixRetrieveRightBraceOrSemiColonPosition", "int", "int", "int")) - .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build()); + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.ASTConverter", "retrieveRightBraceOrSemiColonPosition", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveRightBraceOrSemiColonPosition", "int", "int", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) + .requestExtra(StackRequest.PARAM2) + .transplant() + .build()); + + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.ASTConverter", "retrieveRightBrace", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveRightBraceOrSemiColonPosition", "int", "int", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) + .requestExtra(StackRequest.PARAM2) + .transplant() + .build()); + + sm.addScript(ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.FieldDeclaration")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.ASTConverter", "retrieveRightBrace", "int", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveRightBraceOrSemiColonPosition", "int", "int", "org.eclipse.jdt.internal.compiler.ast.FieldDeclaration")) + .requestExtra(StackRequest.PARAM1) + .transplant() + .build()); + +// sm.addScript(ScriptBuilder.wrapReturnValue() +// .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveRightBraceOrSemiColonPosition")) +// .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveRightBrace")) +// .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveRightBraceOrSemiColonPosition", "int", "int", "int")) +// .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build()); } private static void patchSetGeneratedFlag(ScriptManager sm) { @@ -396,14 +463,14 @@ public class EclipsePatcher extends Agent { return Collections.singleton("org.eclipse.jdt.core.dom.ASTConverter"); } }).request(StackRequest.PARAM1, StackRequest.RETURN_VALUE) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlag", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .transplant().build()); sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) .request(StackRequest.PARAM2, StackRequest.RETURN_VALUE) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlag", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .transplant().build()); @@ -421,7 +488,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVariableDeclarationStatement", "org.eclipse.jdt.core.dom.VariableDeclarationStatement", "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration")) /* Targets above are only patched because the resulting dom nodes should be marked if generated. */ .request(StackRequest.PARAM1, StackRequest.RETURN_VALUE) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlag", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .transplant().build()); @@ -443,7 +510,7 @@ public class EclipsePatcher extends Agent { } }).methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST")) .requestExtra(StackRequest.PARAM1) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); @@ -451,7 +518,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST")) .requestExtra(StackRequest.PARAM2) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); @@ -460,7 +527,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "int", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST")) .requestExtra(StackRequest.PARAM4) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); @@ -468,7 +535,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "int", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.QualifiedName", "<init>", "void", "org.eclipse.jdt.core.dom.AST")) .requestExtra(StackRequest.PARAM4) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); @@ -476,7 +543,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST")) .requestExtra(StackRequest.PARAM3) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); @@ -484,7 +551,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) .methodToWrap(new Hook("org.eclipse.jdt.core.dom.QualifiedName", "<init>", "void", "org.eclipse.jdt.core.dom.AST")) .requestExtra(StackRequest.PARAM3) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void", "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); } @@ -495,7 +562,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget(PARSER_SIG, "parse", "void", "org.eclipse.jdt.internal.compiler.ast.MethodDeclaration", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "checkBit24", "boolean", "java.lang.Object")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "checkBit24", "boolean", "java.lang.Object")) .transplant() .request(StackRequest.PARAM1).build()); @@ -503,7 +570,7 @@ public class EclipsePatcher extends Agent { .target(new MethodTarget(PARSER_SIG, "parse", "void", "org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "boolean")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "checkBit24", "boolean", "java.lang.Object")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "checkBit24", "boolean", "java.lang.Object")) .transplant() .request(StackRequest.PARAM1).build()); @@ -512,7 +579,7 @@ public class EclipsePatcher extends Agent { "org.eclipse.jdt.internal.compiler.ast.Initializer", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration")) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "checkBit24", "boolean", "java.lang.Object")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "checkBit24", "boolean", "java.lang.Object")) .transplant() .request(StackRequest.PARAM1).build()); } @@ -528,12 +595,12 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget(PARSER_SIG, "getMethodBodies", "void", CUD_SIG)) - .wrapMethod(new Hook("lombok.eclipse.TransformEclipseAST", "transform", "void", PARSER_SIG, CUD_SIG)) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Transform", "transform", "void", PARSER_SIG, CUD_SIG)) .request(StackRequest.THIS, StackRequest.PARAM1).build()); sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget(PARSER_SIG, "endParse", CUD_SIG, "int")) - .wrapMethod(new Hook("lombok.eclipse.TransformEclipseAST", "transform_swapped", "void", CUD_SIG, PARSER_SIG)) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Transform", "transform_swapped", "void", CUD_SIG, PARSER_SIG)) .request(StackRequest.THIS, StackRequest.RETURN_VALUE).build()); } @@ -549,7 +616,7 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget(CLASSSCOPE_SIG, "buildFieldsAndMethods", "void")) .request(StackRequest.THIS) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchDelegatePortal", "handleDelegateForType", "boolean", "java.lang.Object")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$Delegate", "handleDelegateForType", "boolean", "java.lang.Object")) .build()); } @@ -579,24 +646,24 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget(PARSER_SIG, "consumeExitVariableWithInitialization", "void")) .request(StackRequest.THIS) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchValEclipsePortal", "copyInitializationOfLocalDeclaration", "void", "java.lang.Object")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$ValPortal", "copyInitializationOfLocalDeclaration", "void", "java.lang.Object")) .build()); sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget(PARSER_SIG, "consumeEnhancedForStatementHeader", "void")) .request(StackRequest.THIS) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchValEclipsePortal", "copyInitializationOfForEachIterable", "void", "java.lang.Object")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$ValPortal", "copyInitializationOfForEachIterable", "void", "java.lang.Object")) .build()); sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget(ASTCONVERTER_SIG, "setModifiers", "void", VARIABLEDECLARATIONSTATEMENT_SIG, LOCALDECLARATION_SIG)) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchValEclipsePortal", "addFinalAndValAnnotationToVariableDeclarationStatement", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$ValPortal", "addFinalAndValAnnotationToVariableDeclarationStatement", "void", "java.lang.Object", "java.lang.Object", "java.lang.Object")) .request(StackRequest.THIS, StackRequest.PARAM1, StackRequest.PARAM2).build()); sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget(ASTCONVERTER_SIG, "setModifiers", "void", SINGLEVARIABLEDECLARATION_SIG, LOCALDECLARATION_SIG)) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchValEclipsePortal", "addFinalAndValAnnotationToSingleVariableDeclaration", + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$ValPortal", "addFinalAndValAnnotationToSingleVariableDeclaration", "void", "java.lang.Object", "java.lang.Object", "java.lang.Object")) .request(StackRequest.THIS, StackRequest.PARAM1, StackRequest.PARAM2).build()); } @@ -611,26 +678,26 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG)) .request(StackRequest.THIS, StackRequest.PARAM1) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchVal", "handleValForLocalDeclaration", "boolean", LOCALDECLARATION_SIG, BLOCKSCOPE_SIG)) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$Val", "handleValForLocalDeclaration", "boolean", LOCALDECLARATION_SIG, BLOCKSCOPE_SIG)) .build()); sm.addScript(ScriptBuilder.replaceMethodCall() .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG)) .methodToReplace(new Hook(EXPRESSION_SIG, "resolveType", TYPEBINDING_SIG, BLOCKSCOPE_SIG)) .requestExtra(StackRequest.THIS) - .replacementMethod(new Hook("lombok.eclipse.agent.PatchVal", "skipResolveInitializerIfAlreadyCalled2", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG, LOCALDECLARATION_SIG)) + .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Val", "skipResolveInitializerIfAlreadyCalled2", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG, LOCALDECLARATION_SIG)) .build()); sm.addScript(ScriptBuilder.replaceMethodCall() .target(new MethodTarget(FOREACHSTATEMENT_SIG, "resolve", "void", BLOCKSCOPE_SIG)) .methodToReplace(new Hook(EXPRESSION_SIG, "resolveType", TYPEBINDING_SIG, BLOCKSCOPE_SIG)) - .replacementMethod(new Hook("lombok.eclipse.agent.PatchVal", "skipResolveInitializerIfAlreadyCalled", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG)) + .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Val", "skipResolveInitializerIfAlreadyCalled", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG)) .build()); sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget(FOREACHSTATEMENT_SIG, "resolve", "void", BLOCKSCOPE_SIG)) .request(StackRequest.THIS, StackRequest.PARAM1) - .decisionMethod(new Hook("lombok.eclipse.agent.PatchVal", "handleValForForEach", "boolean", FOREACHSTATEMENT_SIG, BLOCKSCOPE_SIG)) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$Val", "handleValForForEach", "boolean", FOREACHSTATEMENT_SIG, BLOCKSCOPE_SIG)) .build()); } @@ -641,7 +708,7 @@ public class EclipsePatcher extends Agent { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget(SOURCE_TYPE_CONVERTER_SIG, "convertAnnotations", ANNOTATION_SIG + "[]", I_ANNOTATABLE_SIG)) - .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "convertAnnotations", ANNOTATION_SIG + "[]", ANNOTATION_SIG + "[]", I_ANNOTATABLE_SIG)) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "convertAnnotations", ANNOTATION_SIG + "[]", ANNOTATION_SIG + "[]", I_ANNOTATABLE_SIG)) .request(StackRequest.PARAM1, StackRequest.RETURN_VALUE).build()); } @@ -659,10 +726,11 @@ public class EclipsePatcher extends Agent { } private static void patchExtensionMethod(ScriptManager sm, boolean ecj) { - final String PATCH_EXTENSIONMETHOD = "lombok.eclipse.agent.PatchExtensionMethod"; + final String PATCH_EXTENSIONMETHOD = "lombok.launch.PatchFixesHider$ExtensionMethod"; final String PATCH_EXTENSIONMETHOD_COMPLETIONPROPOSAL_PORTAL = "lombok.eclipse.agent.PatchExtensionMethodCompletionProposalPortal"; final String MESSAGE_SEND_SIG = "org.eclipse.jdt.internal.compiler.ast.MessageSend"; final String TYPE_BINDING_SIG = "org.eclipse.jdt.internal.compiler.lookup.TypeBinding"; + final String SCOPE_SIG = "org.eclipse.jdt.internal.compiler.lookup.Scope"; final String BLOCK_SCOPE_SIG = "org.eclipse.jdt.internal.compiler.lookup.BlockScope"; final String TYPE_BINDINGS_SIG = "org.eclipse.jdt.internal.compiler.lookup.TypeBinding[]"; final String PROBLEM_REPORTER_SIG = "org.eclipse.jdt.internal.compiler.problem.ProblemReporter"; @@ -690,6 +758,13 @@ public class EclipsePatcher extends Agent { .replacementMethod(new Hook(PATCH_EXTENSIONMETHOD, "invalidMethod", "void", PROBLEM_REPORTER_SIG, MESSAGE_SEND_SIG, METHOD_BINDING_SIG)) .build()); + // Since eclipse mars; they added a param. + sm.addScript(replaceMethodCall() + .target(new MethodTarget(MESSAGE_SEND_SIG, "resolveType", TYPE_BINDING_SIG, BLOCK_SCOPE_SIG)) + .methodToReplace(new Hook(PROBLEM_REPORTER_SIG, "invalidMethod", "void", MESSAGE_SEND_SIG, METHOD_BINDING_SIG, SCOPE_SIG)) + .replacementMethod(new Hook(PATCH_EXTENSIONMETHOD, "invalidMethod", "void", PROBLEM_REPORTER_SIG, MESSAGE_SEND_SIG, METHOD_BINDING_SIG, SCOPE_SIG)) + .build()); + if (!ecj) { sm.addScript(wrapReturnValue() .target(new MethodTarget(COMPLETION_PROPOSAL_COLLECTOR_SIG, "getJavaCompletionProposals", I_JAVA_COMPLETION_PROPOSAL_SIG)) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java index b1f5a43a..02760e35 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java @@ -699,7 +699,10 @@ public class PatchDelegate { } private static void addAllMethodBindings0(List<BindingTuple> list, TypeBinding binding, Set<String> banList, char[] fieldName, ASTNode responsible) throws DelegateRecursion { - if (binding instanceof SourceTypeBinding) ((SourceTypeBinding) binding).scope.environment().globalOptions.storeAnnotations = true; + if (binding instanceof SourceTypeBinding) { + ClassScope scope = ((SourceTypeBinding) binding).scope; + if (scope != null) scope.environment().globalOptions.storeAnnotations = true; + } if (binding == null) return; TypeBinding inner; @@ -721,42 +724,44 @@ public class PatchDelegate { } } - if (binding instanceof ReferenceBinding) { - ReferenceBinding rb = (ReferenceBinding) binding; - MethodBinding[] availableMethods = rb.availableMethods(); - FieldBinding[] availableFields = rb.availableFields(); - failIfContainsAnnotation(binding, availableMethods); - failIfContainsAnnotation(binding, availableFields); - - MethodBinding[] parameterizedSigs = availableMethods; - MethodBinding[] baseSigs = parameterizedSigs; - if (binding instanceof ParameterizedTypeBinding) { - baseSigs = ((ParameterizedTypeBinding)binding).genericType().availableMethods(); - if (baseSigs.length != parameterizedSigs.length) { - // The last known state of eclipse source says this can't happen, so we rely on it, - // but if this invariant is broken, better to go with 'arg0' naming instead of crashing. - baseSigs = parameterizedSigs; - } - } - for (int i = 0; i < parameterizedSigs.length; i++) { - MethodBinding mb = parameterizedSigs[i]; - String sig = printSig(mb); - if (mb.isStatic()) continue; - if (mb.isBridge()) continue; - if (mb.isConstructor()) continue; - if (mb.isDefaultAbstract()) continue; - if (!mb.isPublic()) continue; - if (mb.isSynthetic()) continue; - if (!banList.add(sig)) continue; // If add returns false, it was already in there. - BindingTuple pair = new BindingTuple(mb, baseSigs[i], fieldName, responsible); - list.add(pair); - } - addAllMethodBindings0(list, rb.superclass(), banList, fieldName, responsible); - ReferenceBinding[] interfaces = rb.superInterfaces(); - if (interfaces != null) { - for (ReferenceBinding iface : interfaces) addAllMethodBindings0(list, iface, banList, fieldName, responsible); + if (!(binding instanceof ReferenceBinding)) { + return; + } + + ReferenceBinding rb = (ReferenceBinding) binding; + MethodBinding[] availableMethods = rb.availableMethods(); + FieldBinding[] availableFields = rb.availableFields(); + failIfContainsAnnotation(binding, availableMethods); + failIfContainsAnnotation(binding, availableFields); + + MethodBinding[] parameterizedSigs = availableMethods; + MethodBinding[] baseSigs = parameterizedSigs; + if (binding instanceof ParameterizedTypeBinding) { + baseSigs = ((ParameterizedTypeBinding)binding).genericType().availableMethods(); + if (baseSigs.length != parameterizedSigs.length) { + // The last known state of eclipse source says this can't happen, so we rely on it, + // but if this invariant is broken, better to go with 'arg0' naming instead of crashing. + baseSigs = parameterizedSigs; } } + for (int i = 0; i < parameterizedSigs.length; i++) { + MethodBinding mb = parameterizedSigs[i]; + String sig = printSig(mb); + if (mb.isStatic()) continue; + if (mb.isBridge()) continue; + if (mb.isConstructor()) continue; + if (mb.isDefaultAbstract()) continue; + if (!mb.isPublic()) continue; + if (mb.isSynthetic()) continue; + if (!banList.add(sig)) continue; // If add returns false, it was already in there. + BindingTuple pair = new BindingTuple(mb, baseSigs[i], fieldName, responsible); + list.add(pair); + } + addAllMethodBindings0(list, rb.superclass(), banList, fieldName, responsible); + ReferenceBinding[] interfaces = rb.superInterfaces(); + if (interfaces != null) { + for (ReferenceBinding iface : interfaces) addAllMethodBindings0(list, iface, banList, fieldName, responsible); + } } private static final char[] STRING_LOMBOK = new char[] {'l', 'o', 'm', 'b', 'o', 'k'}; diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java index 8eec27fb..5d586dff 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java @@ -24,6 +24,8 @@ package lombok.eclipse.agent; import static lombok.eclipse.handlers.EclipseHandlerUtil.createAnnotation; import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -56,6 +58,7 @@ import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; @@ -89,16 +92,47 @@ public class PatchExtensionMethod { private final ProblemReporter problemReporter; private final WeakReference<MessageSend> messageSendRef; private final MethodBinding method; + private final Scope scope; - PostponedInvalidMethodError(ProblemReporter problemReporter, MessageSend messageSend, MethodBinding method) { + private static final Method shortMethod = getMethod("invalidMethod", MessageSend.class, MethodBinding.class); + private static final Method longMethod = getMethod("invalidMethod", MessageSend.class, MethodBinding.class, Scope.class); + + private static Method getMethod(String name, Class<?>... types) { + try { + Method m = ProblemReporter.class.getMethod(name, types); + m.setAccessible(true); + return m; + } catch (Exception e) { + return null; + } + } + + PostponedInvalidMethodError(ProblemReporter problemReporter, MessageSend messageSend, MethodBinding method, Scope scope) { this.problemReporter = problemReporter; this.messageSendRef = new WeakReference<MessageSend>(messageSend); this.method = method; + this.scope = scope; + } + + static void invoke(ProblemReporter problemReporter, MessageSend messageSend, MethodBinding method, Scope scope) { + if (messageSend != null) { + try { + if (shortMethod != null) shortMethod.invoke(problemReporter, messageSend, method); + else if (longMethod != null) longMethod.invoke(problemReporter, messageSend, method, scope); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof Error) throw (Error) t; + if (t instanceof RuntimeException) throw (RuntimeException) t; + throw new RuntimeException(t); + } + } } public void fire() { MessageSend messageSend = messageSendRef.get(); - if (messageSend != null) problemReporter.invalidMethod(messageSend, method); + invoke(problemReporter, messageSend, method, scope); } } @@ -185,7 +219,11 @@ public class PatchExtensionMethod { } public static void invalidMethod(ProblemReporter problemReporter, MessageSend messageSend, MethodBinding method) { - MessageSend_postponedErrors.set(messageSend, new PostponedInvalidMethodError(problemReporter, messageSend, method)); + MessageSend_postponedErrors.set(messageSend, new PostponedInvalidMethodError(problemReporter, messageSend, method, null)); + } + + public static void invalidMethod(ProblemReporter problemReporter, MessageSend messageSend, MethodBinding method, Scope scope) { + MessageSend_postponedErrors.set(messageSend, new PostponedInvalidMethodError(problemReporter, messageSend, method, scope)); } public static TypeBinding resolveType(TypeBinding resolvedType, MessageSend methodCall, BlockScope scope) { @@ -224,12 +262,16 @@ public class PatchExtensionMethod { if (methodCall.arguments != null) arguments.addAll(Arrays.asList(methodCall.arguments)); List<TypeBinding> argumentTypes = new ArrayList<TypeBinding>(); for (Expression argument : arguments) { - argumentTypes.add(argument.resolvedType); + if (argument.resolvedType != null) argumentTypes.add(argument.resolvedType); + // TODO: Instead of just skipping nulls entirely, there is probably a 'unresolved type' placeholder. THAT is what we ought to be adding here! } + Expression[] originalArgs = methodCall.arguments; + methodCall.arguments = arguments.toArray(new Expression[0]); MethodBinding fixedBinding = scope.getMethod(extensionMethod.declaringClass, methodCall.selector, argumentTypes.toArray(new TypeBinding[0]), methodCall); if (fixedBinding instanceof ProblemMethodBinding) { + methodCall.arguments = originalArgs; if (fixedBinding.declaringClass != null) { - scope.problemReporter().invalidMethod(methodCall, fixedBinding); + PostponedInvalidMethodError.invoke(scope.problemReporter(), methodCall, fixedBinding, scope); } } else { for (int i = 0, iend = arguments.size(); i < iend; i++) { @@ -246,7 +288,6 @@ public class PatchExtensionMethod { arg.implicitConversion = TypeIds.UNBOXING | (id + (id << 4)); // magic see TypeIds } } - methodCall.arguments = arguments.toArray(new Expression[0]); methodCall.receiver = createNameRef(extensionMethod.declaringClass, methodCall); methodCall.actualReceiverType = extensionMethod.declaringClass; diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java index 97ca5a7e..c11a49cd 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java @@ -60,8 +60,6 @@ import org.eclipse.jdt.ui.text.java.CompletionProposalCollector; import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; public class PatchExtensionMethodCompletionProposal { - - public static IJavaCompletionProposal[] getJavaCompletionProposals(IJavaCompletionProposal[] javaCompletionProposals, CompletionProposalCollector completionProposalCollector) { @@ -178,7 +176,7 @@ public class PatchExtensionMethodCompletionProposal { return !proposals.isEmpty() && Reflection.isComplete(); } - private static int getReplacementOffset(IJavaCompletionProposal proposal) { + private static int getReplacementOffset(Object proposal) { try { return Reflection.replacementOffsetField.getInt(proposal); } catch (Exception ignore) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java index 6dca1901..19e1952e 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java @@ -33,7 +33,6 @@ public class PatchExtensionMethodCompletionProposalPortal { private static final String COMPLETION_PROPOSAL_COLLECTOR = "org.eclipse.jdt.ui.text.java.CompletionProposalCollector"; private static final String I_JAVA_COMPLETION_PROPOSAL_ARRAY = "[Lorg.eclipse.jdt.ui.text.java.IJavaCompletionProposal;"; - public static IJavaCompletionProposal[] getJavaCompletionProposals(Object[] javaCompletionProposals, Object completionProposalCollector) { try { return (IJavaCompletionProposal[]) ReflectionForUi.getJavaCompletionProposals.invoke(null, javaCompletionProposals, completionProposalCollector); @@ -52,7 +51,7 @@ public class PatchExtensionMethodCompletionProposalPortal { } //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly //do anything useful here. - return (IJavaCompletionProposal[])javaCompletionProposals; + return (IJavaCompletionProposal[]) javaCompletionProposals; } } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java deleted file mode 100644 index d1c668a0..00000000 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (C) 2010-2013 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 - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package lombok.eclipse.agent; - -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -import lombok.core.DiagnosticsReceiver; -import lombok.core.PostCompiler; -import lombok.core.Version; -import lombok.eclipse.EclipseAugments; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IAnnotatable; -import org.eclipse.jdt.core.IAnnotation; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jdt.core.dom.SimpleName; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.core.dom.rewrite.NodeRewriteEvent; -import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; -import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; -import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; - -public class PatchFixes { - public static String addLombokNotesToEclipseAboutDialog(String origReturnValue, String key) { - if ("aboutText".equals(key)) { - return origReturnValue + "\n\nLombok " + Version.getFullVersion() + " is installed. http://projectlombok.org/"; - } - - return origReturnValue; - } - - public static boolean isGenerated(org.eclipse.jdt.core.dom.ASTNode node) { - boolean result = false; - try { - result = ((Boolean)node.getClass().getField("$isGenerated").get(node)).booleanValue(); - if (!result && node.getParent() != null && node.getParent() instanceof org.eclipse.jdt.core.dom.QualifiedName) - result = isGenerated(node.getParent()); - } catch (Exception e) { - // better to assume it isn't generated - } - return result; - } - - public static boolean isListRewriteOnGeneratedNode(org.eclipse.jdt.core.dom.rewrite.ListRewrite rewrite) { - return isGenerated(rewrite.getParent()); - } - - public static boolean returnFalse(java.lang.Object object) { - return false; - } - - public static boolean returnTrue(java.lang.Object object) { - return true; - } - - @java.lang.SuppressWarnings({"unchecked", "rawtypes"}) public static java.util.List removeGeneratedNodes(java.util.List list) { - try { - java.util.List realNodes = new java.util.ArrayList(list.size()); - for (java.lang.Object node : list) { - if(!isGenerated(((org.eclipse.jdt.core.dom.ASTNode)node))) { - realNodes.add(node); - } - } - return realNodes; - } catch (Exception e) { - } - return list; - } - - public static java.lang.String getRealMethodDeclarationSource(java.lang.String original, Object processor, org.eclipse.jdt.core.dom.MethodDeclaration declaration) throws Exception { - if (!isGenerated(declaration)) return original; - - List<org.eclipse.jdt.core.dom.Annotation> annotations = new ArrayList<org.eclipse.jdt.core.dom.Annotation>(); - for (Object modifier : declaration.modifiers()) { - if (modifier instanceof org.eclipse.jdt.core.dom.Annotation) { - org.eclipse.jdt.core.dom.Annotation annotation = (org.eclipse.jdt.core.dom.Annotation)modifier; - String qualifiedAnnotationName = annotation.resolveTypeBinding().getQualifiedName(); - if (!"java.lang.Override".equals(qualifiedAnnotationName) && !"java.lang.SuppressWarnings".equals(qualifiedAnnotationName)) annotations.add(annotation); - } - } - - StringBuilder signature = new StringBuilder(); - addAnnotations(annotations, signature); - - if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); - if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); - - signature - .append(declaration.getReturnType2().toString()) - .append(" ").append(declaration.getName().getFullyQualifiedName()) - .append("("); - - boolean first = true; - for (Object parameter : declaration.parameters()) { - if (!first) signature.append(", "); - first = false; - // We should also add the annotations of the parameters - signature.append(parameter); - } - - signature.append(");"); - return signature.toString(); - } - - // part of getRealMethodDeclarationSource(...) - public static void addAnnotations(List<org.eclipse.jdt.core.dom.Annotation> annotations, StringBuilder signature) { - /* - * We SHOULD be able to handle the following cases: - * @Override - * @Override() - * @SuppressWarnings("all") - * @SuppressWarnings({"all", "unused"}) - * @SuppressWarnings(value = "all") - * @SuppressWarnings(value = {"all", "unused"}) - * @EqualsAndHashCode(callSuper=true, of="id") - * - * Currently, we only seem to correctly support: - * @Override - * @Override() N.B. We lose the parentheses here, since there are no values. No big deal. - * @SuppressWarnings("all") - */ - for (org.eclipse.jdt.core.dom.Annotation annotation : annotations) { - List<String> values = new ArrayList<String>(); - if (annotation.isSingleMemberAnnotation()) { - org.eclipse.jdt.core.dom.SingleMemberAnnotation smAnn = (org.eclipse.jdt.core.dom.SingleMemberAnnotation) annotation; - values.add(smAnn.getValue().toString()); - } else if (annotation.isNormalAnnotation()) { - org.eclipse.jdt.core.dom.NormalAnnotation normalAnn = (org.eclipse.jdt.core.dom.NormalAnnotation) annotation; - for (Object value : normalAnn.values()) values.add(value.toString()); - } - - signature.append("@").append(annotation.resolveTypeBinding().getQualifiedName()); - if (!values.isEmpty()) { - signature.append("("); - boolean first = true; - for (String string : values) { - if (!first) signature.append(", "); - first = false; - signature.append('"').append(string).append('"'); - } - signature.append(")"); - } - signature.append(" "); - } - } - - public static org.eclipse.jdt.core.dom.MethodDeclaration getRealMethodDeclarationNode(org.eclipse.jdt.core.IMethod sourceMethod, org.eclipse.jdt.core.dom.CompilationUnit cuUnit) throws JavaModelException { - MethodDeclaration methodDeclarationNode = ASTNodeSearchUtil.getMethodDeclarationNode(sourceMethod, cuUnit); - if (isGenerated(methodDeclarationNode)) { - IType declaringType = sourceMethod.getDeclaringType(); - Stack<IType> typeStack = new Stack<IType>(); - while (declaringType != null) { - typeStack.push(declaringType); - declaringType = declaringType.getDeclaringType(); - } - - IType rootType = typeStack.pop(); - org.eclipse.jdt.core.dom.AbstractTypeDeclaration typeDeclaration = findTypeDeclaration(rootType, cuUnit.types()); - while (!typeStack.isEmpty() && typeDeclaration != null) { - typeDeclaration = findTypeDeclaration(typeStack.pop(), typeDeclaration.bodyDeclarations()); - } - - if (typeStack.isEmpty() && typeDeclaration != null) { - String methodName = sourceMethod.getElementName(); - for (Object declaration : typeDeclaration.bodyDeclarations()) { - if (declaration instanceof org.eclipse.jdt.core.dom.MethodDeclaration) { - org.eclipse.jdt.core.dom.MethodDeclaration methodDeclaration = (org.eclipse.jdt.core.dom.MethodDeclaration) declaration; - if (methodDeclaration.getName().toString().equals(methodName)) { - return methodDeclaration; - } - } - } - } - } - return methodDeclarationNode; - } - - // part of getRealMethodDeclarationNode - public static org.eclipse.jdt.core.dom.AbstractTypeDeclaration findTypeDeclaration(IType searchType, List<?> nodes) { - for (Object object : nodes) { - if (object instanceof org.eclipse.jdt.core.dom.AbstractTypeDeclaration) { - org.eclipse.jdt.core.dom.AbstractTypeDeclaration typeDeclaration = (org.eclipse.jdt.core.dom.AbstractTypeDeclaration) object; - if (typeDeclaration.getName().toString().equals(searchType.getElementName())) - return typeDeclaration; - } - } - return null; - } - - public static int getSourceEndFixed(int sourceEnd, org.eclipse.jdt.internal.compiler.ast.ASTNode node) throws Exception { - if (sourceEnd == -1) { - org.eclipse.jdt.internal.compiler.ast.ASTNode object = (org.eclipse.jdt.internal.compiler.ast.ASTNode)node.getClass().getField("$generatedBy").get(node); - if (object != null) { - return object.sourceEnd; - } - } - return sourceEnd; - } - - public static int fixRetrieveStartingCatchPosition(int original, int start) { - return original == -1 ? start : original; - } - - public static int fixRetrieveIdentifierEndPosition(int original, int end) { - return original == -1 ? end : original; - } - - public static int fixRetrieveEllipsisStartPosition(int original, int end) { - return original == -1 ? end : original; - } - - public static int fixRetrieveRightBraceOrSemiColonPosition(int original, int end) { -// return original; - return original == -1 ? end : original; // Need to fix: see issue 325. - } - - public static final int ALREADY_PROCESSED_FLAG = 0x800000; //Bit 24 - - public static boolean checkBit24(Object node) throws Exception { - int bits = (Integer)(node.getClass().getField("bits").get(node)); - return (bits & ALREADY_PROCESSED_FLAG) != 0; - } - - public static boolean skipRewritingGeneratedNodes(org.eclipse.jdt.core.dom.ASTNode node) throws Exception { - return ((Boolean)node.getClass().getField("$isGenerated").get(node)).booleanValue(); - } - - public static void setIsGeneratedFlag(org.eclipse.jdt.core.dom.ASTNode domNode, - org.eclipse.jdt.internal.compiler.ast.ASTNode internalNode) throws Exception { - if (internalNode == null || domNode == null) return; - boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get(internalNode) != null; - if (isGenerated) domNode.getClass().getField("$isGenerated").set(domNode, true); - } - - public static void setIsGeneratedFlagForName(org.eclipse.jdt.core.dom.Name name, Object internalNode) throws Exception { - if (internalNode instanceof org.eclipse.jdt.internal.compiler.ast.ASTNode) { - if (EclipseAugments.ASTNode_generatedBy.get((org.eclipse.jdt.internal.compiler.ast.ASTNode) internalNode) != null) { - name.getClass().getField("$isGenerated").set(name, true); - } - } - } - - public static RewriteEvent[] listRewriteHandleGeneratedMethods(RewriteEvent parent) { - RewriteEvent[] children = parent.getChildren(); - List<RewriteEvent> newChildren = new ArrayList<RewriteEvent>(); - List<RewriteEvent> modifiedChildren = new ArrayList<RewriteEvent>(); - for (int i=0; i<children.length; i++) { - RewriteEvent child = children[i]; - boolean isGenerated = isGenerated( (org.eclipse.jdt.core.dom.ASTNode)child.getOriginalValue() ); - if (isGenerated) { - if ((child.getChangeKind() == RewriteEvent.REPLACED || child.getChangeKind() == RewriteEvent.REMOVED) - && child.getOriginalValue() instanceof org.eclipse.jdt.core.dom.MethodDeclaration - && child.getNewValue() != null - ) { - modifiedChildren.add(new NodeRewriteEvent(null, child.getNewValue())); - } - } else { - newChildren.add(child); - } - } - // Since Eclipse doesn't honor the "insert at specified location" for already existing members, - // we'll just add them last - newChildren.addAll(modifiedChildren); - return newChildren.toArray(new RewriteEvent[newChildren.size()]); - } - - public static int getTokenEndOffsetFixed(TokenScanner scanner, int token, int startOffset, Object domNode) throws CoreException { - boolean isGenerated = false; - try { - isGenerated = (Boolean) domNode.getClass().getField("$isGenerated").get(domNode); - } catch (Exception e) { - // If this fails, better to break some refactor scripts than to crash eclipse. - } - if (isGenerated) return -1; - return scanner.getTokenEndOffset(token, startOffset); - } - - public static IMethod[] removeGeneratedMethods(IMethod[] methods) throws Exception { - List<IMethod> result = new ArrayList<IMethod>(); - for (IMethod m : methods) { - if (m.getNameRange().getLength() > 0 && !m.getNameRange().equals(m.getSourceRange())) result.add(m); - } - return result.size() == methods.length ? methods : result.toArray(new IMethod[result.size()]); - } - - public static SimpleName[] removeGeneratedSimpleNames(SimpleName[] in) throws Exception { - Field f = SimpleName.class.getField("$isGenerated"); - - int count = 0; - for (int i = 0; i < in.length; i++) { - if (in[i] == null || !((Boolean)f.get(in[i])).booleanValue()) count++; - } - if (count == in.length) return in; - SimpleName[] newSimpleNames = new SimpleName[count]; - count = 0; - for (int i = 0; i < in.length; i++) { - if (in[i] == null || !((Boolean)f.get(in[i])).booleanValue()) newSimpleNames[count++] = in[i]; - } - return newSimpleNames; - } - - public static byte[] runPostCompiler(byte[] bytes, String fileName) { - byte[] transformed = PostCompiler.applyTransformations(bytes, fileName, DiagnosticsReceiver.CONSOLE); - return transformed == null ? bytes : transformed; - } - - public static OutputStream runPostCompiler(OutputStream out) throws IOException { - return PostCompiler.wrapOutputStream(out, "TEST", DiagnosticsReceiver.CONSOLE); - } - - public static BufferedOutputStream runPostCompiler(BufferedOutputStream out, String path, String name) throws IOException { - String fileName = path + "/" + name; - return new BufferedOutputStream(PostCompiler.wrapOutputStream(out, fileName, DiagnosticsReceiver.CONSOLE)); - } - - public static Annotation[] convertAnnotations(Annotation[] out, IAnnotatable annotatable) { - IAnnotation[] in; - - try { - in = annotatable.getAnnotations(); - } catch (Exception e) { - return out; - } - - if (out == null) return null; - int toWrite = 0; - - for (int idx = 0; idx < out.length; idx++) { - String oName = new String(out[idx].type.getLastToken()); - boolean found = false; - for (IAnnotation i : in) { - String name = i.getElementName(); - int li = name.lastIndexOf('.'); - if (li > -1) name = name.substring(li + 1); - if (name.equals(oName)) { - found = true; - break; - } - } - if (!found) out[idx] = null; - else toWrite++; - } - - Annotation[] replace = out; - if (toWrite < out.length) { - replace = new Annotation[toWrite]; - int idx = 0; - for (int i = 0; i < out.length; i++) { - if (out[i] == null) continue; - replace[idx++] = out[i]; - } - } - - return replace; - } -} diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java new file mode 100644 index 00000000..52f63765 --- /dev/null +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixesShadowLoaded.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.agent; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import lombok.core.DiagnosticsReceiver; +import lombok.core.PostCompiler; +import lombok.core.Version; + +public class PatchFixesShadowLoaded { + public static String addLombokNotesToEclipseAboutDialog(String origReturnValue, String key) { + if ("aboutText".equals(key)) { + return origReturnValue + "\n\nLombok " + Version.getFullVersion() + " is installed. https://projectlombok.org/"; + } + return origReturnValue; + } + + public static byte[] runPostCompiler(byte[] bytes, String fileName) { + byte[] transformed = PostCompiler.applyTransformations(bytes, fileName, DiagnosticsReceiver.CONSOLE); + return transformed == null ? bytes : transformed; + } + + public static OutputStream runPostCompiler(OutputStream out) throws IOException { + return PostCompiler.wrapOutputStream(out, "TEST", DiagnosticsReceiver.CONSOLE); + } + + public static BufferedOutputStream runPostCompiler(BufferedOutputStream out, String path, String name) throws IOException { + String fileName = path + "/" + name; + return new BufferedOutputStream(PostCompiler.wrapOutputStream(out, fileName, DiagnosticsReceiver.CONSOLE)); + } +} diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index e734dceb..3da37869 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 The Project Lombok Authors. + * Copyright (C) 2010-2018 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 @@ -21,11 +21,6 @@ */ package lombok.eclipse.agent; -import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import static lombok.eclipse.Eclipse.*; - -import java.lang.reflect.Field; - import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; @@ -43,6 +38,11 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import java.lang.reflect.Field; + +import static lombok.eclipse.Eclipse.poss; +import static lombok.eclipse.handlers.EclipseHandlerUtil.makeType; + public class PatchVal { // This is half of the work for 'val' support - the other half is in PatchValEclipse. This half is enough for ecj. @@ -57,6 +57,9 @@ public class PatchVal { return expr.resolveType(scope); } catch (NullPointerException e) { return null; + } catch (ArrayIndexOutOfBoundsException e) { + // This will occur internally due to for example 'val x = mth("X");', where mth takes 2 arguments. + return null; } } @@ -66,6 +69,9 @@ public class PatchVal { return expr.resolveType(scope); } catch (NullPointerException e) { return null; + } catch (ArrayIndexOutOfBoundsException e) { + // This will occur internally due to for example 'val x = mth("X");', where mth takes 2 arguments. + return null; } } @@ -78,31 +84,44 @@ public class PatchVal { return true; } - public static boolean couldBeVal(TypeReference ref) { + public static boolean couldBe(String key, TypeReference ref) { + String[] keyParts = key.split("\\."); if (ref instanceof SingleTypeReference) { char[] token = ((SingleTypeReference)ref).token; - return matches("val", token); + return matches(keyParts[keyParts.length - 1], token); } if (ref instanceof QualifiedTypeReference) { char[][] tokens = ((QualifiedTypeReference)ref).tokens; - if (tokens == null || tokens.length != 2) return false; - return matches("lombok", tokens[0]) && matches("val", tokens[1]); + if (keyParts.length != tokens.length) return false; + for(int i = 0; i < tokens.length; ++i) { + String part = keyParts[i]; + char[] token = tokens[i]; + if (!matches(part, token)) return false; + } + return true; } return false; } - - private static boolean isVal(TypeReference ref, BlockScope scope) { - if (!couldBeVal(ref)) return false; - + + private static boolean is(TypeReference ref, BlockScope scope, String key) { + if (!couldBe(key, ref)) return false; + TypeBinding resolvedType = ref.resolvedType; if (resolvedType == null) resolvedType = ref.resolveType(scope, false); if (resolvedType == null) return false; char[] pkg = resolvedType.qualifiedPackageName(); char[] nm = resolvedType.qualifiedSourceName(); - return matches("lombok", pkg) && matches("val", nm); + int pkgFullLength = pkg.length > 0 ? pkg.length + 1: 0; + char[] fullName = new char[pkgFullLength + nm.length]; + if(pkg.length > 0) { + System.arraycopy(pkg, 0, fullName, 0, pkg.length); + fullName[pkg.length] = '.'; + } + System.arraycopy(nm, 0, fullName, pkgFullLength, nm.length); + return matches(key, fullName); } public static final class Reflection { @@ -126,9 +145,20 @@ public class PatchVal { if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false; boolean decomponent = false; - if (!isVal(local.type, scope)) return false; + boolean val = isVal(local, scope); + boolean var = isVar(local, scope); + if (!(val || var)) return false; - if (new Throwable().getStackTrace()[2].getClassName().contains("ForStatement")) return false; + StackTraceElement[] st = new Throwable().getStackTrace(); + for (int i = 0; i < st.length - 2 && i < 10; i++) { + if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) { + boolean valInForStatement = val && + st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && + st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement"); + if (valInForStatement) return false; + break; + } + } Expression init = local.initialization; if (init == null && Reflection.initCopyField != null) { @@ -157,7 +187,7 @@ public class PatchVal { TypeBinding resolved = null; try { - resolved = decomponent ? getForEachComponentType(init, scope) : init.resolveType(scope); + resolved = decomponent ? getForEachComponentType(init, scope) : resolveForExpression(init, scope); } catch (NullPointerException e) { // This definitely occurs if as part of resolving the initializer expression, a // lambda expression in it must also be resolved (such as when lambdas are part of @@ -174,23 +204,33 @@ public class PatchVal { } } - local.modifiers |= ClassFileConstants.AccFinal; + if(val) local.modifiers |= ClassFileConstants.AccFinal; local.annotations = addValAnnotation(local.annotations, local.type, scope); local.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(local.type, 3)); return false; } + private static boolean isVar(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.experimental.var") || is(local.type, scope, "lombok.var"); + } + + private static boolean isVal(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.val"); + } + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { if (forEach.elementVariable == null) return false; - if (!isVal(forEach.elementVariable.type, scope)) return false; + boolean val = isVal(forEach.elementVariable, scope); + boolean var = isVar(forEach.elementVariable, scope); + if (!(val || var)) return false; TypeBinding component = getForEachComponentType(forEach.collection, scope); if (component == null) return false; TypeReference replacement = makeType(component, forEach.elementVariable.type, false); - forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; + if (val) forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; forEach.elementVariable.annotations = addValAnnotation(forEach.elementVariable.annotations, forEach.elementVariable.type, scope); forEach.elementVariable.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3)); @@ -215,7 +255,7 @@ public class PatchVal { private static TypeBinding getForEachComponentType(Expression collection, BlockScope scope) { if (collection != null) { TypeBinding resolved = collection.resolvedType; - if (resolved == null) resolved = collection.resolveType(scope); + if (resolved == null) resolved = resolveForExpression(collection, scope); if (resolved == null) return null; if (resolved.isArrayType()) { resolved = ((ArrayBinding) resolved).elementsType(); @@ -243,4 +283,13 @@ public class PatchVal { return null; } + + private static TypeBinding resolveForExpression(Expression collection, BlockScope scope) { + try { + return collection.resolveType(scope); + } catch (ArrayIndexOutOfBoundsException e) { + // Known cause of issues; for example: val e = mth("X"), where mth takes 2 arguments. + return null; + } + } } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index 7d5f36f4..46237dcf 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 The Project Lombok Authors. + * Copyright (C) 2010-2018 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 @@ -47,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.parser.Parser; @@ -65,7 +66,9 @@ public class PatchValEclipse { ForeachStatement foreachDecl = (ForeachStatement) astStack[astPtr]; ASTNode init = foreachDecl.collection; if (init == null) return; - if (foreachDecl.elementVariable == null || !PatchVal.couldBeVal(foreachDecl.elementVariable.type)) return; + boolean val = couldBeVal(foreachDecl.elementVariable.type); + boolean var = couldBeVar(foreachDecl.elementVariable.type); + if (foreachDecl.elementVariable == null || !(val || var)) return; try { if (Reflection.iterableCopyField != null) Reflection.iterableCopyField.set(foreachDecl.elementVariable, init); @@ -88,7 +91,9 @@ public class PatchValEclipse { if (!(variableDecl instanceof LocalDeclaration)) return; ASTNode init = variableDecl.initialization; if (init == null) return; - if (!PatchVal.couldBeVal(variableDecl.type)) return; + boolean val = couldBeVal(variableDecl.type); + boolean var = couldBeVar(variableDecl.type); + if (!(val || var)) return; try { if (Reflection.initCopyField != null) Reflection.initCopyField.set(variableDecl, init); @@ -97,6 +102,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVar(TypeReference type) { + return PatchVal.couldBe("lombok.experimental.var", type) || PatchVal.couldBe("lombok.var", type); + } + public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, SingleVariableDeclaration out, LocalDeclaration in) { @SuppressWarnings("unchecked") List<IExtendedModifier> modifiers = out.modifiers(); addFinalAndValAnnotationToModifierList(converter, modifiers, out.getAST(), in); @@ -115,7 +124,7 @@ public class PatchValEclipse { Annotation valAnnotation = null; for (Annotation ann : in.annotations) { - if (PatchVal.couldBeVal(ann.type)) { + if (couldBeVal(ann.type)) { found = true; valAnnotation = ann; break; @@ -167,6 +176,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVal(TypeReference type) { + return PatchVal.couldBe("lombok.val", type); + } + public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) { Modifier modifier = null; try { diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java new file mode 100644 index 00000000..b1d73352 --- /dev/null +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2010-2015 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.launch; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import lombok.eclipse.EclipseAugments; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IAnnotatable; +import org.eclipse.jdt.core.IAnnotation; +import org.eclipse.jdt.core.IField; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.parser.Parser; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.core.SourceField; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeRewriteEvent; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; +import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; +import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; +import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; + +/** These contain a mix of the following: + * <ul> + * <li> 'dependency free' method wrappers that cross the shadowloader barrier. + * <li> methods that directly patch, <em>but</em>, these should ALWAYS be transplanted. + * </ul> + * + * <strong>This class lives on the outside of the shadowloader barrier, and as a consequence, cannot access any other lombok code except other + * code in the {@code lombok.launch} package!</strong>. + * <p> + * This class is package private with lots of public inner static classes. This hides all of them from IDE autocomplete dialogs and such but at the JVM + * level the inner static class are just plain public, which is important, because calls to the contents of these inner static classes are injected into + * various eclipse classes verbatim, and if they weren't public, the verifier wouldn't accept it. + */ +final class PatchFixesHider { + + /** These utility methods are only used 'internally', but because of transplant methods, the class (and its methods) still have to be public! */ + public static final class Util { + private static ClassLoader shadowLoader; + + public static Class<?> shadowLoadClass(String name) { + try { + if (shadowLoader == null) { + try { + Class.forName("lombok.core.LombokNode"); + // If we get here, then lombok is already available. + shadowLoader = Util.class.getClassLoader(); + } catch (ClassNotFoundException e) { + // If we get here, it isn't, and we should use the shadowloader. + shadowLoader = Main.createShadowClassLoader(); + } + } + + return Class.forName(name, true, shadowLoader); + } catch (ClassNotFoundException e) { + throw sneakyThrow(e); + } + } + + public static Method findMethod(Class<?> type, String name, Class<?>... parameterTypes) { + try { + return type.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException e) { + throw sneakyThrow(e); + } + } + + public static Object invokeMethod(Method method, Object... args) { + try { + return method.invoke(null, args); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } + } + + private static RuntimeException sneakyThrow(Throwable t) { + if (t == null) throw new NullPointerException("t"); + Util.<RuntimeException>sneakyThrow0(t); + return null; + } + + @SuppressWarnings("unchecked") + private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T { + throw (T)t; + } + } + + /** Contains patch fixes that are dependent on lombok internals. */ + public static final class LombokDeps { + public static final Method ADD_LOMBOK_NOTES; + public static final Method POST_COMPILER_BYTES_STRING; + public static final Method POST_COMPILER_OUTPUTSTREAM; + public static final Method POST_COMPILER_BUFFEREDOUTPUTSTREAM_STRING_STRING; + + static { + Class<?> shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchFixesShadowLoaded"); + ADD_LOMBOK_NOTES = Util.findMethod(shadowed, "addLombokNotesToEclipseAboutDialog", String.class, String.class); + POST_COMPILER_BYTES_STRING = Util.findMethod(shadowed, "runPostCompiler", byte[].class, String.class); + POST_COMPILER_OUTPUTSTREAM = Util.findMethod(shadowed, "runPostCompiler", OutputStream.class); + POST_COMPILER_BUFFEREDOUTPUTSTREAM_STRING_STRING = Util.findMethod(shadowed, "runPostCompiler", BufferedOutputStream.class, String.class, String.class); + } + + public static String addLombokNotesToEclipseAboutDialog(String origReturnValue, String key) { + return (String) Util.invokeMethod(LombokDeps.ADD_LOMBOK_NOTES, origReturnValue, key); + } + + public static byte[] runPostCompiler(byte[] bytes, String fileName) { + return (byte[]) Util.invokeMethod(LombokDeps.POST_COMPILER_BYTES_STRING, bytes, fileName); + } + + public static OutputStream runPostCompiler(OutputStream out) throws IOException { + return (OutputStream) Util.invokeMethod(LombokDeps.POST_COMPILER_OUTPUTSTREAM, out); + } + + public static BufferedOutputStream runPostCompiler(BufferedOutputStream out, String path, String name) throws IOException { + return (BufferedOutputStream) Util.invokeMethod(LombokDeps.POST_COMPILER_BUFFEREDOUTPUTSTREAM_STRING_STRING, out, path, name); + } + } + + public static final class Transform { + private static final Method TRANSFORM; + private static final Method TRANSFORM_SWAPPED; + + static { + Class<?> shadowed = Util.shadowLoadClass("lombok.eclipse.TransformEclipseAST"); + TRANSFORM = Util.findMethod(shadowed, "transform", Parser.class, CompilationUnitDeclaration.class); + TRANSFORM_SWAPPED = Util.findMethod(shadowed, "transform_swapped", CompilationUnitDeclaration.class, Parser.class); + } + + public static void transform(Parser parser, CompilationUnitDeclaration ast) throws IOException { + Util.invokeMethod(TRANSFORM, parser, ast); + } + + public static void transform_swapped(CompilationUnitDeclaration ast, Parser parser) throws IOException { + Util.invokeMethod(TRANSFORM_SWAPPED, ast, parser); + } + } + + /** Contains patch code to support {@code @Delegate} */ + public static final class Delegate { + private static final Method HANDLE_DELEGATE_FOR_TYPE; + + static { + Class<?> shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchDelegatePortal"); + HANDLE_DELEGATE_FOR_TYPE = Util.findMethod(shadowed, "handleDelegateForType", Object.class); + } + + public static boolean handleDelegateForType(Object classScope) { + return (Boolean) Util.invokeMethod(HANDLE_DELEGATE_FOR_TYPE, classScope); + } + } + + /** Contains patch code to support {@code val} (eclipse specific) */ + public static final class ValPortal { + private static final Method COPY_INITIALIZATION_OF_FOR_EACH_ITERABLE; + private static final Method COPY_INITIALIZATION_OF_LOCAL_DECLARATION; + private static final Method ADD_FINAL_AND_VAL_ANNOTATION_TO_VARIABLE_DECLARATION_STATEMENT; + private static final Method ADD_FINAL_AND_VAL_ANNOTATION_TO_SINGLE_VARIABLE_DECLARATION; + + static { + Class<?> shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchValEclipsePortal"); + COPY_INITIALIZATION_OF_FOR_EACH_ITERABLE = Util.findMethod(shadowed, "copyInitializationOfForEachIterable", Object.class); + COPY_INITIALIZATION_OF_LOCAL_DECLARATION = Util.findMethod(shadowed, "copyInitializationOfLocalDeclaration", Object.class); + ADD_FINAL_AND_VAL_ANNOTATION_TO_VARIABLE_DECLARATION_STATEMENT = Util.findMethod(shadowed, "addFinalAndValAnnotationToVariableDeclarationStatement", Object.class, Object.class, Object.class); + ADD_FINAL_AND_VAL_ANNOTATION_TO_SINGLE_VARIABLE_DECLARATION = Util.findMethod(shadowed, "addFinalAndValAnnotationToSingleVariableDeclaration", Object.class, Object.class, Object.class); + } + + public static void copyInitializationOfForEachIterable(Object parser) { + Util.invokeMethod(COPY_INITIALIZATION_OF_FOR_EACH_ITERABLE, parser); + } + + public static void copyInitializationOfLocalDeclaration(Object parser) { + Util.invokeMethod(COPY_INITIALIZATION_OF_LOCAL_DECLARATION, parser); + } + + public static void addFinalAndValAnnotationToVariableDeclarationStatement(Object converter, Object out, Object in) { + Util.invokeMethod(ADD_FINAL_AND_VAL_ANNOTATION_TO_VARIABLE_DECLARATION_STATEMENT, converter, out, in); + } + + public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, Object out, Object in) { + Util.invokeMethod(ADD_FINAL_AND_VAL_ANNOTATION_TO_SINGLE_VARIABLE_DECLARATION, converter, out, in); + } + } + + /** Contains patch code to support {@code val} (eclipse and ecj) */ + public static final class Val { + private static final Method SKIP_RESOLVE_INITIALIZER_IF_ALREADY_CALLED; + private static final Method SKIP_RESOLVE_INITIALIZER_IF_ALREADY_CALLED2; + private static final Method HANDLE_VAL_FOR_LOCAL_DECLARATION; + private static final Method HANDLE_VAL_FOR_FOR_EACH; + + static { + Class<?> shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchVal"); + SKIP_RESOLVE_INITIALIZER_IF_ALREADY_CALLED = Util.findMethod(shadowed, "skipResolveInitializerIfAlreadyCalled", Expression.class, BlockScope.class); + SKIP_RESOLVE_INITIALIZER_IF_ALREADY_CALLED2 = Util.findMethod(shadowed, "skipResolveInitializerIfAlreadyCalled2", Expression.class, BlockScope.class, LocalDeclaration.class); + HANDLE_VAL_FOR_LOCAL_DECLARATION = Util.findMethod(shadowed, "handleValForLocalDeclaration", LocalDeclaration.class, BlockScope.class); + HANDLE_VAL_FOR_FOR_EACH = Util.findMethod(shadowed, "handleValForForEach", ForeachStatement.class, BlockScope.class); + } + + public static TypeBinding skipResolveInitializerIfAlreadyCalled(Expression expr, BlockScope scope) { + return (TypeBinding) Util.invokeMethod(SKIP_RESOLVE_INITIALIZER_IF_ALREADY_CALLED, expr, scope); + } + + public static TypeBinding skipResolveInitializerIfAlreadyCalled2(Expression expr, BlockScope scope, LocalDeclaration decl) { + return (TypeBinding) Util.invokeMethod(SKIP_RESOLVE_INITIALIZER_IF_ALREADY_CALLED2, expr, scope, decl); + } + + public static boolean handleValForLocalDeclaration(LocalDeclaration local, BlockScope scope) { + return (Boolean) Util.invokeMethod(HANDLE_VAL_FOR_LOCAL_DECLARATION, local, scope); + } + + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { + return (Boolean) Util.invokeMethod(HANDLE_VAL_FOR_FOR_EACH, forEach, scope); + } + } + + /** Contains patch code to support {@code @ExtensionMethod} */ + public static final class ExtensionMethod { + private static final Method RESOLVE_TYPE; + private static final Method ERROR_NO_METHOD_FOR; + private static final Method INVALID_METHOD, INVALID_METHOD2; + + static { + Class<?> shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchExtensionMethod"); + RESOLVE_TYPE = Util.findMethod(shadowed, "resolveType", TypeBinding.class, MessageSend.class, BlockScope.class); + ERROR_NO_METHOD_FOR = Util.findMethod(shadowed, "errorNoMethodFor", ProblemReporter.class, MessageSend.class, TypeBinding.class, TypeBinding[].class); + INVALID_METHOD = Util.findMethod(shadowed, "invalidMethod", ProblemReporter.class, MessageSend.class, MethodBinding.class); + INVALID_METHOD2 = Util.findMethod(shadowed, "invalidMethod", ProblemReporter.class, MessageSend.class, MethodBinding.class, Scope.class); + } + + public static TypeBinding resolveType(TypeBinding resolvedType, MessageSend methodCall, BlockScope scope) { + return (TypeBinding) Util.invokeMethod(RESOLVE_TYPE, resolvedType, methodCall, scope); + } + + public static void errorNoMethodFor(ProblemReporter problemReporter, MessageSend messageSend, TypeBinding recType, TypeBinding[] params) { + Util.invokeMethod(ERROR_NO_METHOD_FOR, problemReporter, messageSend, recType, params); + } + + public static void invalidMethod(ProblemReporter problemReporter, MessageSend messageSend, MethodBinding method) { + Util.invokeMethod(INVALID_METHOD, problemReporter, messageSend, method); + } + + public static void invalidMethod(ProblemReporter problemReporter, MessageSend messageSend, MethodBinding method, Scope scope) { + Util.invokeMethod(INVALID_METHOD2, problemReporter, messageSend, method, scope); + } + } + + /** + * Contains a mix of methods: ecj only, ecj+eclipse, and eclipse only. As a consequence, _EVERY_ method from here used for ecj MUST be + * transplanted, as ecj itself cannot load this class (signatures refer to things that don't exist in ecj-only mode). + * <p> + * Because of usage of transplant(), a bunch of these contain direct code and don't try to cross the shadowloader barrier. + */ + public static final class PatchFixes { + public static boolean isGenerated(org.eclipse.jdt.core.dom.ASTNode node) { + boolean result = false; + try { + result = ((Boolean)node.getClass().getField("$isGenerated").get(node)).booleanValue(); + if (!result && node.getParent() != null && node.getParent() instanceof org.eclipse.jdt.core.dom.QualifiedName) { + result = isGenerated(node.getParent()); + } + } catch (Exception e) { + // better to assume it isn't generated + } + return result; + } + + public static boolean isListRewriteOnGeneratedNode(org.eclipse.jdt.core.dom.rewrite.ListRewrite rewrite) { + return isGenerated(rewrite.getParent()); + } + + public static boolean returnFalse(java.lang.Object object) { + return false; + } + + public static boolean returnTrue(java.lang.Object object) { + return true; + } + + @java.lang.SuppressWarnings({"unchecked", "rawtypes"}) public static java.util.List removeGeneratedNodes(java.util.List list) { + try { + java.util.List realNodes = new java.util.ArrayList(list.size()); + for (java.lang.Object node : list) { + if(!isGenerated(((org.eclipse.jdt.core.dom.ASTNode)node))) { + realNodes.add(node); + } + } + return realNodes; + } catch (Exception e) { + } + return list; + } + + public static java.lang.String getRealMethodDeclarationSource(java.lang.String original, Object processor, org.eclipse.jdt.core.dom.MethodDeclaration declaration) throws Exception { + if (!isGenerated(declaration)) return original; + + List<org.eclipse.jdt.core.dom.Annotation> annotations = new ArrayList<org.eclipse.jdt.core.dom.Annotation>(); + for (Object modifier : declaration.modifiers()) { + if (modifier instanceof org.eclipse.jdt.core.dom.Annotation) { + org.eclipse.jdt.core.dom.Annotation annotation = (org.eclipse.jdt.core.dom.Annotation)modifier; + String qualifiedAnnotationName = annotation.resolveTypeBinding().getQualifiedName(); + if (!"java.lang.Override".equals(qualifiedAnnotationName) && !"java.lang.SuppressWarnings".equals(qualifiedAnnotationName)) annotations.add(annotation); + } + } + + StringBuilder signature = new StringBuilder(); + addAnnotations(annotations, signature); + + if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); + if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); + + signature + .append(declaration.getReturnType2().toString()) + .append(" ").append(declaration.getName().getFullyQualifiedName()) + .append("("); + + boolean first = true; + for (Object parameter : declaration.parameters()) { + if (!first) signature.append(", "); + first = false; + // We should also add the annotations of the parameters + signature.append(parameter); + } + + signature.append(");"); + return signature.toString(); + } + + // part of getRealMethodDeclarationSource(...) + public static void addAnnotations(List<org.eclipse.jdt.core.dom.Annotation> annotations, StringBuilder signature) { + /* + * We SHOULD be able to handle the following cases: + * @Override + * @Override() + * @SuppressWarnings("all") + * @SuppressWarnings({"all", "unused"}) + * @SuppressWarnings(value = "all") + * @SuppressWarnings(value = {"all", "unused"}) + * @EqualsAndHashCode(callSuper=true, of="id") + * + * Currently, we only seem to correctly support: + * @Override + * @Override() N.B. We lose the parentheses here, since there are no values. No big deal. + * @SuppressWarnings("all") + */ + for (org.eclipse.jdt.core.dom.Annotation annotation : annotations) { + List<String> values = new ArrayList<String>(); + if (annotation.isSingleMemberAnnotation()) { + org.eclipse.jdt.core.dom.SingleMemberAnnotation smAnn = (org.eclipse.jdt.core.dom.SingleMemberAnnotation) annotation; + values.add(smAnn.getValue().toString()); + } else if (annotation.isNormalAnnotation()) { + org.eclipse.jdt.core.dom.NormalAnnotation normalAnn = (org.eclipse.jdt.core.dom.NormalAnnotation) annotation; + for (Object value : normalAnn.values()) values.add(value.toString()); + } + + signature.append("@").append(annotation.resolveTypeBinding().getQualifiedName()); + if (!values.isEmpty()) { + signature.append("("); + boolean first = true; + for (String string : values) { + if (!first) signature.append(", "); + first = false; + signature.append('"').append(string).append('"'); + } + signature.append(")"); + } + signature.append(" "); + } + } + + public static org.eclipse.jdt.core.dom.MethodDeclaration getRealMethodDeclarationNode(org.eclipse.jdt.core.IMethod sourceMethod, org.eclipse.jdt.core.dom.CompilationUnit cuUnit) throws JavaModelException { + MethodDeclaration methodDeclarationNode = ASTNodeSearchUtil.getMethodDeclarationNode(sourceMethod, cuUnit); + if (isGenerated(methodDeclarationNode)) { + IType declaringType = sourceMethod.getDeclaringType(); + Stack<IType> typeStack = new Stack<IType>(); + while (declaringType != null) { + typeStack.push(declaringType); + declaringType = declaringType.getDeclaringType(); + } + + IType rootType = typeStack.pop(); + org.eclipse.jdt.core.dom.AbstractTypeDeclaration typeDeclaration = findTypeDeclaration(rootType, cuUnit.types()); + while (!typeStack.isEmpty() && typeDeclaration != null) { + typeDeclaration = findTypeDeclaration(typeStack.pop(), typeDeclaration.bodyDeclarations()); + } + + if (typeStack.isEmpty() && typeDeclaration != null) { + String methodName = sourceMethod.getElementName(); + for (Object declaration : typeDeclaration.bodyDeclarations()) { + if (declaration instanceof org.eclipse.jdt.core.dom.MethodDeclaration) { + org.eclipse.jdt.core.dom.MethodDeclaration methodDeclaration = (org.eclipse.jdt.core.dom.MethodDeclaration) declaration; + if (methodDeclaration.getName().toString().equals(methodName)) { + return methodDeclaration; + } + } + } + } + } + return methodDeclarationNode; + } + + // part of getRealMethodDeclarationNode + public static org.eclipse.jdt.core.dom.AbstractTypeDeclaration findTypeDeclaration(IType searchType, List<?> nodes) { + for (Object object : nodes) { + if (object instanceof org.eclipse.jdt.core.dom.AbstractTypeDeclaration) { + org.eclipse.jdt.core.dom.AbstractTypeDeclaration typeDeclaration = (org.eclipse.jdt.core.dom.AbstractTypeDeclaration) object; + if (typeDeclaration.getName().toString().equals(searchType.getElementName())) + return typeDeclaration; + } + } + return null; + } + + public static int getSourceEndFixed(int sourceEnd, org.eclipse.jdt.internal.compiler.ast.ASTNode node) throws Exception { + if (sourceEnd == -1) { + org.eclipse.jdt.internal.compiler.ast.ASTNode object = (org.eclipse.jdt.internal.compiler.ast.ASTNode)node.getClass().getField("$generatedBy").get(node); + if (object != null) { + return object.sourceEnd; + } + } + return sourceEnd; + } + + public static int fixRetrieveStartingCatchPosition(int original, int start) { + return original == -1 ? start : original; + } + + public static int fixRetrieveIdentifierEndPosition(int original, int end) { + return original == -1 ? end : original; + } + + public static int fixRetrieveEllipsisStartPosition(int original, int end) { + return original == -1 ? end : original; + } + + public static int fixRetrieveRightBraceOrSemiColonPosition(int original, int end) { +// if (original == -1) { +// Thread.dumpStack(); +// } + return original == -1 ? end : original; + } + + public static int fixRetrieveRightBraceOrSemiColonPosition(int retVal, AbstractMethodDeclaration amd) { + if (retVal != -1 || amd == null) return retVal; + boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get(amd) != null; + if (isGenerated) return amd.declarationSourceEnd; + return -1; + } + + public static int fixRetrieveRightBraceOrSemiColonPosition(int retVal, FieldDeclaration fd) { + if (retVal != -1 || fd == null) return retVal; + boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get(fd) != null; + if (isGenerated) return fd.declarationSourceEnd; + return -1; + } + + public static final int ALREADY_PROCESSED_FLAG = 0x800000; //Bit 24 + + public static boolean checkBit24(Object node) throws Exception { + int bits = (Integer)(node.getClass().getField("bits").get(node)); + return (bits & ALREADY_PROCESSED_FLAG) != 0; + } + + public static boolean skipRewritingGeneratedNodes(org.eclipse.jdt.core.dom.ASTNode node) throws Exception { + return ((Boolean) node.getClass().getField("$isGenerated").get(node)).booleanValue(); + } + + public static void setIsGeneratedFlag(org.eclipse.jdt.core.dom.ASTNode domNode, + org.eclipse.jdt.internal.compiler.ast.ASTNode internalNode) throws Exception { + + if (internalNode == null || domNode == null) return; + boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get(internalNode) != null; + if (isGenerated) domNode.getClass().getField("$isGenerated").set(domNode, true); + } + + public static void setIsGeneratedFlagForName(org.eclipse.jdt.core.dom.Name name, Object internalNode) throws Exception { + if (internalNode instanceof org.eclipse.jdt.internal.compiler.ast.ASTNode) { + boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get((org.eclipse.jdt.internal.compiler.ast.ASTNode) internalNode) != null; + if (isGenerated) name.getClass().getField("$isGenerated").set(name, true); + } + } + + public static RewriteEvent[] listRewriteHandleGeneratedMethods(RewriteEvent parent) { + RewriteEvent[] children = parent.getChildren(); + List<RewriteEvent> newChildren = new ArrayList<RewriteEvent>(); + List<RewriteEvent> modifiedChildren = new ArrayList<RewriteEvent>(); + for (int i = 0; i < children.length; i++) { + RewriteEvent child = children[i]; + boolean isGenerated = isGenerated((org.eclipse.jdt.core.dom.ASTNode) child.getOriginalValue()); + if (isGenerated) { + boolean isReplacedOrRemoved = child.getChangeKind() == RewriteEvent.REPLACED || child.getChangeKind() == RewriteEvent.REMOVED; + boolean convertingFromMethod = child.getOriginalValue() instanceof org.eclipse.jdt.core.dom.MethodDeclaration; + if (isReplacedOrRemoved && convertingFromMethod && child.getNewValue() != null) { + modifiedChildren.add(new NodeRewriteEvent(null, child.getNewValue())); + } + } else { + newChildren.add(child); + } + } + // Since Eclipse doesn't honor the "insert at specified location" for already existing members, + // we'll just add them last + newChildren.addAll(modifiedChildren); + return newChildren.toArray(new RewriteEvent[newChildren.size()]); + } + + public static int getTokenEndOffsetFixed(TokenScanner scanner, int token, int startOffset, Object domNode) throws CoreException { + boolean isGenerated = false; + try { + isGenerated = (Boolean) domNode.getClass().getField("$isGenerated").get(domNode); + } catch (Exception e) { + // If this fails, better to break some refactor scripts than to crash eclipse. + } + if (isGenerated) return -1; + return scanner.getTokenEndOffset(token, startOffset); + } + + public static IMethod[] removeGeneratedMethods(IMethod[] methods) throws Exception { + List<IMethod> result = new ArrayList<IMethod>(); + for (IMethod m : methods) { + if (m.getNameRange().getLength() > 0 && !m.getNameRange().equals(m.getSourceRange())) result.add(m); + } + return result.size() == methods.length ? methods : result.toArray(new IMethod[result.size()]); + } + + public static SearchMatch[] removeGenerated(SearchMatch[] returnValue) { + List<SearchMatch> result = new ArrayList<SearchMatch>(); + for (int j = 0; j < returnValue.length; j++) { + SearchMatch searchResult = returnValue[j]; + if (searchResult.getElement() instanceof IField) { + IField field = (IField) searchResult.getElement(); + + // can not check for value=lombok because annotation is + // not fully resolved + IAnnotation annotation = field.getAnnotation("Generated"); + if (annotation != null) { + // Method generated at field location, skip + continue; + } + + } + result.add(searchResult); + } + return result.toArray(new SearchMatch[result.size()]); + } + + public static SearchResultGroup[] createFakeSearchResult(SearchResultGroup[] returnValue, + Object/* + * org.eclipse.jdt.internal.corext.refactoring.rename. + * RenameFieldProcessor + */ processor) throws Exception { + if (returnValue == null || returnValue.length == 0) { + // if no matches were found, check if Data annotation is present on the class + Field declaredField = processor.getClass().getDeclaredField("fField"); + if (declaredField != null) { + declaredField.setAccessible(true); + SourceField fField = (SourceField) declaredField.get(processor); + IAnnotation dataAnnotation = fField.getDeclaringType().getAnnotation("Data"); + if (dataAnnotation != null) { + // add fake item, to make refactoring checks pass + return new SearchResultGroup[] {new SearchResultGroup(null, new SearchMatch[1])}; + } + } + } + return returnValue; + } + + public static SimpleName[] removeGeneratedSimpleNames(SimpleName[] in) throws Exception { + Field f = SimpleName.class.getField("$isGenerated"); + + int count = 0; + for (int i = 0; i < in.length; i++) { + if (in[i] == null || !((Boolean)f.get(in[i])).booleanValue()) count++; + } + if (count == in.length) return in; + SimpleName[] newSimpleNames = new SimpleName[count]; + count = 0; + for (int i = 0; i < in.length; i++) { + if (in[i] == null || !((Boolean)f.get(in[i])).booleanValue()) newSimpleNames[count++] = in[i]; + } + return newSimpleNames; + } + + public static Annotation[] convertAnnotations(Annotation[] out, IAnnotatable annotatable) { + IAnnotation[] in; + + try { + in = annotatable.getAnnotations(); + } catch (Exception e) { + return out; + } + + if (out == null) return null; + int toWrite = 0; + + for (int idx = 0; idx < out.length; idx++) { + String oName = new String(out[idx].type.getLastToken()); + boolean found = false; + for (IAnnotation i : in) { + String name = i.getElementName(); + int li = name.lastIndexOf('.'); + if (li > -1) name = name.substring(li + 1); + if (name.equals(oName)) { + found = true; + break; + } + } + if (!found) out[idx] = null; + else toWrite++; + } + + Annotation[] replace = out; + if (toWrite < out.length) { + replace = new Annotation[toWrite]; + int idx = 0; + for (int i = 0; i < out.length; i++) { + if (out[i] == null) continue; + replace[idx++] = out[i]; + } + } + + return replace; + } + } +} |