aboutsummaryrefslogtreecommitdiff
path: root/src_eclipseagent/lombok/eclipse/agent/EclipsePatcher.java
diff options
context:
space:
mode:
Diffstat (limited to 'src_eclipseagent/lombok/eclipse/agent/EclipsePatcher.java')
-rw-r--r--src_eclipseagent/lombok/eclipse/agent/EclipsePatcher.java214
1 files changed, 125 insertions, 89 deletions
diff --git a/src_eclipseagent/lombok/eclipse/agent/EclipsePatcher.java b/src_eclipseagent/lombok/eclipse/agent/EclipsePatcher.java
index 7659302c..c39a7d4e 100644
--- a/src_eclipseagent/lombok/eclipse/agent/EclipsePatcher.java
+++ b/src_eclipseagent/lombok/eclipse/agent/EclipsePatcher.java
@@ -21,24 +21,18 @@
*/
package lombok.eclipse.agent;
-import java.io.File;
-import java.io.IOException;
-import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URI;
-import java.net.URLDecoder;
-import java.nio.charset.Charset;
-import java.security.ProtectionDomain;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.jar.JarFile;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
-import lombok.Lombok;
-import lombok.core.SpiLoadUtil;
+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.scripts.ScriptBuilder;
/**
* This is a java-agent that patches some of eclipse's classes so AST Nodes are handed off to Lombok
@@ -50,85 +44,127 @@ import lombok.core.SpiLoadUtil;
public class EclipsePatcher {
private EclipsePatcher() {}
- private static Map<String, EclipseTransformer> transformers = new HashMap<String, EclipseTransformer>();
- static {
- try {
- for ( EclipseTransformer transformer : SpiLoadUtil.findServices(EclipseTransformer.class) ) {
- String targetClassName = transformer.getTargetClassName();
- transformers.put(targetClassName, transformer);
- }
- } catch ( Throwable t ) {
- throw Lombok.sneakyThrow(t);
- }
- }
-
- private static class Patcher implements ClassFileTransformer {
- public byte[] transform(ClassLoader loader, String className,
- Class<?> classBeingRedefined,
- ProtectionDomain protectionDomain, byte[] classfileBuffer)
- throws IllegalClassFormatException {
-
-// ClassLoader classLoader = Patcher.class.getClassLoader();
-// if ( classLoader == null ) classLoader = ClassLoader.getSystemClassLoader();
-
- EclipseTransformer transformer = transformers.get(className);
- if ( transformer != null ) return transformer.transform(classfileBuffer);
-
- return null;
- }
- }
-
public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
- registerPatcher(instrumentation, true);
- addLombokToSearchPaths(instrumentation);
- }
-
- private static void addLombokToSearchPaths(Instrumentation instrumentation) throws Exception {
- String path = findPathOfOurClassloader();
- //On java 1.5, you don't have these methods, so you'll be forced to manually -Xbootclasspath/a them in.
- tryCallMethod(instrumentation, "appendToSystemClassLoaderSearch", path + "/lombok.jar");
- tryCallMethod(instrumentation, "appendToBootstrapClassLoaderSearch", path + "/lombok.eclipse.agent.jar");
- }
-
- private static void tryCallMethod(Object o, String methodName, String path) {
- try {
- Instrumentation.class.getMethod(methodName, JarFile.class).invoke(o, new JarFile(path));
- } catch ( Throwable ignore ) {}
- }
-
- private static String findPathOfOurClassloader() throws Exception {
- URI uri = EclipsePatcher.class.getResource("/" + EclipsePatcher.class.getName().replace('.', '/') + ".class").toURI();
- Pattern p = Pattern.compile("^jar:file:([^\\!]+)\\!.*\\.class$");
- Matcher m = p.matcher(uri.toString());
- if ( !m.matches() ) return ".";
- String rawUri = m.group(1);
- return new File(URLDecoder.decode(rawUri, Charset.defaultCharset().name())).getParent();
+ registerPatchScripts(instrumentation, true);
}
public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
- registerPatcher(instrumentation, false);
- addLombokToSearchPaths(instrumentation);
+ registerPatchScripts(instrumentation, false);
}
- private static void registerPatcher(Instrumentation instrumentation, boolean transformExisting) throws IOException {
- instrumentation.addTransformer(new Patcher()/*, true*/);
+ private static void registerPatchScripts(Instrumentation instrumentation, boolean reloadExistingClasses) {
+ ScriptManager sm = new ScriptManager();
+ sm.registerTransformer(instrumentation);
+ EquinoxClassLoader.getInstance().addPrefix("lombok.");
+ EquinoxClassLoader.getInstance().registerScripts(sm);
+
+ sm.addScript(ScriptBuilder.wrapReturnValue()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveStartingCatchPosition"))
+ .wrapMethod(new Hook("lombok/eclipse/agent/PatchFixes", "fixRetrieveStartingCatchPosition", "(I)I"))
+ .transplant().request(StackRequest.PARAM1).build());
+
+ sm.addScript(ScriptBuilder.addField()
+ .targetClass("org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration")
+ .fieldName("$lombokAST").fieldType("Ljava/lang/Object;")
+ .setPublic().setTransient().build());
+
+ final String PARSER_SIG1 = "org.eclipse.jdt.internal.compiler.parser.Parser";
+ final String PARSER_SIG2 = "Lorg/eclipse/jdt/internal/compiler/parser/Parser;";
+ final String CUD_SIG1 = "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration";
+ final String CUD_SIG2 = "Lorg/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration;";
+
+ sm.addScript(ScriptBuilder.wrapReturnValue()
+ .target(new MethodTarget(PARSER_SIG1, "getMethodBodies", "void", CUD_SIG1))
+ .wrapMethod(new Hook("lombok/eclipse/TransformEclipseAST", "transform",
+ "(" + PARSER_SIG2 + CUD_SIG2 + ")V"))
+ .request(StackRequest.THIS, StackRequest.PARAM1).build());
+
+ sm.addScript(ScriptBuilder.wrapReturnValue()
+ .target(new MethodTarget(PARSER_SIG1, "endParse", CUD_SIG1, "int"))
+ .wrapMethod(new Hook("lombok/eclipse/TransformEclipseAST", "transform_swapped",
+ "(" + CUD_SIG2 + PARSER_SIG2 + ")V"))
+ .request(StackRequest.THIS, StackRequest.RETURN_VALUE).build());
+
+ sm.addScript(ScriptBuilder.exitEarly()
+ .target(new MethodTarget(PARSER_SIG1, "parse", "void",
+ "org.eclipse.jdt.internal.compiler.ast.MethodDeclaration",
+ "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration"))
+ .decisionMethod(new Hook("lombok/eclipse/agent/PatchFixes", "checkBit24", "(Ljava/lang/Object;)Z"))
+ .transplant().request(StackRequest.PARAM1).build());
+
+ sm.addScript(ScriptBuilder.exitEarly()
+ .target(new MethodTarget(PARSER_SIG1, "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", "(Ljava/lang/Object;)Z"))
+ .transplant().request(StackRequest.PARAM1).build());
+
+ sm.addScript(ScriptBuilder.exitEarly()
+ .target(new MethodTarget(PARSER_SIG1, "parse", "void",
+ "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", "(Ljava/lang/Object;)Z"))
+ .transplant().request(StackRequest.PARAM1).build());
+
+ sm.addScript(ScriptBuilder.addField()
+ .targetClass("org.eclipse.jdt.internal.compiler.ast.ASTNode")
+ .fieldName("$generatedBy")
+ .fieldType("Lorg/eclipse/jdt/internal/compiler/ast/ASTNode;")
+ .setPublic().setTransient().build());
+
+ sm.addScript(ScriptBuilder.addField()
+ .targetClass("org.eclipse.jdt.core.dom.ASTNode")
+ .fieldName("$isGenerated").fieldType("Z")
+ .setPublic().setTransient().build());
+
+ sm.addScript(ScriptBuilder.wrapReturnValue()
+ .target(new TargetMatcher() {
+ @Override public boolean matches(String classSpec, String methodName, String descriptor) {
+ if (!"convert".equals(methodName)) return false;
+
+ List<String> fullDesc = MethodTarget.decomposeFullDesc(descriptor);
+ if ("V".equals(fullDesc.get(0))) return false;
+ if (fullDesc.size() < 2) return false;
+ if (!fullDesc.get(1).startsWith("Lorg/eclipse/jdt/internal/compiler/ast/")) return false;
+ return true;
+ }
+
+ @Override public Collection<String> getAffectedClasses() {
+ return Collections.singleton("org.eclipse.jdt.core.dom.ASTConverter");
+ }
+ }).request(StackRequest.PARAM1, StackRequest.RETURN_VALUE)
+ .wrapMethod(new Hook("lombok/eclipse/agent/PatchFixes", "setIsGeneratedFlag",
+ "(Lorg/eclipse/jdt/core/dom/ASTNode;Lorg/eclipse/jdt/internal/compiler/ast/ASTNode;)V"))
+ .transplant().build());
+
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new TargetMatcher() {
+ @Override public boolean matches(String classSpec, String methodName, String descriptor) {
+ if (!methodName.startsWith("convert")) return false;
+
+ List<String> fullDesc = MethodTarget.decomposeFullDesc(descriptor);
+ if (fullDesc.size() < 2) return false;
+ if (!fullDesc.get(1).startsWith("Lorg/eclipse/jdt/internal/compiler/ast/")) return false;
+
+ return true;
+ }
+
+ @Override public Collection<String> getAffectedClasses() {
+ return Collections.singleton("org.eclipse.jdt.core.dom.ASTConverter");
+ }
+ }).methodToWrap(new Hook("org/eclipse/jdt/core/dom/SimpleName", "<init>", "(Lorg/eclipse/jdt/core/dom/AST;)V"))
+ .requestExtra(StackRequest.PARAM1)
+ .replacementMethod(new Hook("lombok/eclipse/agent/PatchFixes", "setIsGeneratedFlagForSimpleName",
+ "(Lorg/eclipse/jdt/core/dom/SimpleName;Ljava/lang/Object;)V"))
+ .transplant().build());
+
+ sm.addScript(ScriptBuilder.wrapReturnValue()
+ .target(new MethodTarget("org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder", "findByNode"))
+ .wrapMethod(new Hook("lombok/eclipse/agent/PatchFixes", "removeGeneratedSimpleNames",
+ "([Lorg/eclipse/jdt/core/dom/SimpleName;)[Lorg/eclipse/jdt/core/dom/SimpleName;"))
+ .request(StackRequest.RETURN_VALUE).build());
- if ( transformExisting ) for ( Class<?> c : instrumentation.getAllLoadedClasses() ) {
- if ( transformers.containsKey(c.getName()) ) {
- try {
- //instrumentation.retransformClasses(c); - //not in java 1.5.
- Instrumentation.class.getMethod("retransformClasses", Class[].class).invoke(instrumentation,
- new Object[] { new Class[] {c }});
- } catch ( InvocationTargetException e ) {
- throw new UnsupportedOperationException(
- "The eclipse parser class is already loaded and cannot be modified. " +
- "You'll have to restart eclipse in order to use Lombok in eclipse.");
- } catch ( Throwable t ) {
- throw new UnsupportedOperationException(
- "This appears to be a java 1.5 instance, which cannot reload already loaded classes. " +
- "You'll have to restart eclipse in order to use Lombok in eclipse.");
- }
- }
- }
+ if (reloadExistingClasses) sm.reloadClasses(instrumentation);
}
}