mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 18:15:55 +00:00
Merge branch 'fixDelombok'
This commit is contained in:
commit
40b76b5046
47 files changed
+284
-1237
No files matched your search
@@ -130,10 +130,8 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
|
||||
<ivy:compile destdir="build/lombok" source="1.6" target="1.6">
|
||||
<src path="src/core" />
|
||||
<src path="src/delombok" />
|
||||
<src path="src/netbeansAgent" />
|
||||
<include name="lombok/javac/**" />
|
||||
<include name="lombok/delombok/**" />
|
||||
<include name="lombok/netbeans/**" />
|
||||
<classpath location="build/lombok" />
|
||||
<classpath refid="build.path" />
|
||||
</ivy:compile>
|
||||
@@ -165,7 +163,6 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
|
||||
<ivy:eclipsegen>
|
||||
<srcdir dir="src/core" />
|
||||
<srcdir dir="src/eclipseAgent" />
|
||||
<srcdir dir="src/netbeansAgent" />
|
||||
<srcdir dir="src/installer" />
|
||||
<srcdir dir="src/delombok" />
|
||||
<srcdir dir="experimental/src" />
|
||||
@@ -250,7 +247,6 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
|
||||
<sources>
|
||||
<fileset dir="src/core" />
|
||||
<fileset dir="src/eclipseAgent" />
|
||||
<fileset dir="src/netbeansAgent" />
|
||||
<fileset dir="src/installer" />
|
||||
<fileset dir="src/delombok" />
|
||||
<fileset dir="experimental/src" />
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
|
||||
* Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -19,8 +19,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package lombok;
|
||||
|
||||
/**
|
||||
* Contains the mechanism that instruments netbeans by being loaded as a javaagent.
|
||||
*/
|
||||
package lombok.netbeans.agent;
|
||||
public @interface Delegate {
|
||||
Class<?> value() default java.lang.Object.class;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans.
|
||||
* Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -51,7 +51,7 @@ public class HandlerLibrary {
|
||||
private final Map<String, AnnotationHandlerContainer<?>> annotationHandlers = new HashMap<String, AnnotationHandlerContainer<?>>();
|
||||
private final Collection<JavacASTVisitor> visitorHandlers = new ArrayList<JavacASTVisitor>();
|
||||
private final Messager messager;
|
||||
private boolean skipPrintAST = true;
|
||||
private int phase = 0;
|
||||
|
||||
/**
|
||||
* Creates a new HandlerLibrary that will report any problems or errors to the provided messager.
|
||||
@@ -70,6 +70,10 @@ public class HandlerLibrary {
|
||||
this.annotationClass = annotationClass;
|
||||
}
|
||||
|
||||
public boolean isResolutionBased() {
|
||||
return handler.isResolutionBased();
|
||||
}
|
||||
|
||||
public boolean handle(final JavacNode node) {
|
||||
return handler.handle(Javac.createAnnotation(annotationClass, node), (JCAnnotation)node.get(), node);
|
||||
}
|
||||
@@ -160,12 +164,14 @@ public class HandlerLibrary {
|
||||
boolean handled = false;
|
||||
for (String fqn : resolver.findTypeMatches(node, rawType)) {
|
||||
boolean isPrintAST = fqn.equals(PrintAST.class.getName());
|
||||
if (isPrintAST == skipPrintAST) continue;
|
||||
if (isPrintAST && phase != 2) continue;
|
||||
if (!isPrintAST && phase == 2) continue;
|
||||
AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
|
||||
if (container == null) continue;
|
||||
|
||||
try {
|
||||
handled |= container.handle(node);
|
||||
if (container.isResolutionBased() && phase == 1) handled |= container.handle(node);
|
||||
if (!container.isResolutionBased() && phase == 0) handled |= container.handle(node);
|
||||
} catch (AnnotationValueDecodeFail fail) {
|
||||
fail.owner.setError(fail.getMessage(), fail.idx);
|
||||
} catch (Throwable t) {
|
||||
@@ -183,13 +189,8 @@ public class HandlerLibrary {
|
||||
*/
|
||||
public void callASTVisitors(JavacAST ast) {
|
||||
for (JavacASTVisitor visitor : visitorHandlers) try {
|
||||
if (!visitor.isResolutionBased()) ast.traverse(visitor);
|
||||
} catch (Throwable t) {
|
||||
javacError(String.format("Lombok visitor handler %s failed", visitor.getClass()), t);
|
||||
}
|
||||
|
||||
for (JavacASTVisitor visitor : visitorHandlers) try {
|
||||
if (visitor.isResolutionBased()) ast.traverse(visitor);
|
||||
if (!visitor.isResolutionBased() && phase == 0) ast.traverse(visitor);
|
||||
if (visitor.isResolutionBased() && phase == 1) ast.traverse(visitor);
|
||||
} catch (Throwable t) {
|
||||
javacError(String.format("Lombok visitor handler %s failed", visitor.getClass()), t);
|
||||
}
|
||||
@@ -197,17 +198,17 @@ public class HandlerLibrary {
|
||||
|
||||
/**
|
||||
* Lombok does not currently support triggering annotations in a specified order; the order is essentially
|
||||
* random right now. This lack of order is particularly annoying for the {@code PrintAST} annotation,
|
||||
* which is almost always intended to run last. Hence, this hack, which lets it in fact run last.
|
||||
*
|
||||
* @see #skipAllButPrintAST()
|
||||
* random right now. As a temporary hack we've identified 3 important phases.
|
||||
*/
|
||||
public void skipPrintAST() {
|
||||
skipPrintAST = true;
|
||||
public void setPreResolutionPhase() {
|
||||
phase = 0;
|
||||
}
|
||||
|
||||
/** @see #skipPrintAST() */
|
||||
public void skipAllButPrintAST() {
|
||||
skipPrintAST = false;
|
||||
public void setPostResolutionPhase() {
|
||||
phase = 1;
|
||||
}
|
||||
|
||||
public void setPrintASTPhase() {
|
||||
phase = 2;
|
||||
}
|
||||
}
|
||||
@@ -55,4 +55,9 @@ public interface JavacAnnotationHandler<T extends Annotation> {
|
||||
* compile session (you've handled it), or {@code false} to indicate you aren't done yet.
|
||||
*/
|
||||
boolean handle(AnnotationValues<T> annotation, JCAnnotation ast, JavacNode annotationNode);
|
||||
|
||||
/**
|
||||
* Return true if this handler requires resolution.
|
||||
*/
|
||||
boolean isResolutionBased();
|
||||
}
|
||||
@@ -325,6 +325,8 @@ public class JavacResolution {
|
||||
// NB: There's such a thing as maker.Type(type), but this doesn't work very well; it screws up anonymous classes, captures, and adds an extra prefix dot for some reason too.
|
||||
// -- so we write our own take on that here.
|
||||
|
||||
if (type.tag == TypeTags.BOT) return createJavaLangObject(maker, ast);
|
||||
|
||||
if (type.isPrimitive()) return primitiveToJCTree(type.getKind(), maker);
|
||||
if (type.isErroneous()) throw new TypeNotConvertibleException("Type cannot be resolved");
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
package lombok.javac;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
|
||||
@@ -32,6 +31,7 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
public class JavacTransformer {
|
||||
private final HandlerLibrary handlers;
|
||||
@@ -42,26 +42,46 @@ public class JavacTransformer {
|
||||
this.handlers = HandlerLibrary.load(messager);
|
||||
}
|
||||
|
||||
public boolean transform(Context context, Iterable<JCCompilationUnit> compilationUnits) {
|
||||
List<JavacAST> asts = new ArrayList<JavacAST>();
|
||||
public void transform(boolean postResolution, Context context, java.util.List<JCCompilationUnit> compilationUnitsRaw) {
|
||||
List<JCCompilationUnit> compilationUnits;
|
||||
if (compilationUnitsRaw instanceof List<?>) {
|
||||
compilationUnits = (List<JCCompilationUnit>)compilationUnitsRaw;
|
||||
} else {
|
||||
compilationUnits = List.nil();
|
||||
for (int i = compilationUnitsRaw.size() -1; i >= 0; i--) {
|
||||
compilationUnits = compilationUnits.prepend(compilationUnitsRaw.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
java.util.List<JavacAST> asts = new ArrayList<JavacAST>();
|
||||
|
||||
for (JCCompilationUnit unit : compilationUnits) asts.add(new JavacAST(messager, context, unit));
|
||||
|
||||
handlers.skipPrintAST();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
handlers.callASTVisitors(ast);
|
||||
if (!postResolution) {
|
||||
handlers.setPreResolutionPhase();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
handlers.callASTVisitors(ast);
|
||||
}
|
||||
}
|
||||
|
||||
handlers.skipAllButPrintAST();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
if (postResolution) {
|
||||
handlers.setPostResolutionPhase();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
handlers.callASTVisitors(ast);
|
||||
}
|
||||
|
||||
handlers.setPrintASTPhase();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
}
|
||||
}
|
||||
|
||||
for (JavacAST ast : asts) {
|
||||
if (ast.isChanged()) return true;
|
||||
TrackChangedAsts changes = context.get(TrackChangedAsts.class);
|
||||
if (changes != null) for (JavacAST ast : asts) {
|
||||
if (ast.isChanged()) changes.changed.add((JCCompilationUnit) ast.top().get());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private class AnnotationVisitor extends JavacASTAdapter {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package lombok.javac;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
|
||||
public class TrackChangedAsts {
|
||||
public final Set<JCCompilationUnit> changed = new HashSet<JCCompilationUnit>();
|
||||
}
|
||||
@@ -21,13 +21,19 @@
|
||||
*/
|
||||
package lombok.javac.apt;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.JavaFileObject.Kind;
|
||||
|
||||
import lombok.core.DiagnosticsReceiver;
|
||||
@@ -42,6 +48,22 @@ final class InterceptingJavaFileManager implements JavaFileManager {
|
||||
}
|
||||
|
||||
@Override public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
|
||||
if (className.startsWith("lombok.dummy.ForceNewRound")) {
|
||||
String name = className.replace(".", "/") + kind.extension;
|
||||
return new SimpleJavaFileObject(URI.create(name), kind) {
|
||||
@Override public OutputStream openOutputStream() throws IOException {
|
||||
return new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
@Override public InputStream openInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(new byte[0]);
|
||||
}
|
||||
|
||||
@Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
JavaFileObject fileObject = delegate.getJavaFileForOutput(location, className, kind, sibling);
|
||||
if (kind != Kind.CLASS) {
|
||||
return fileObject;
|
||||
|
||||
@@ -23,9 +23,11 @@ package lombok.javac.apt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
@@ -40,7 +42,9 @@ import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import lombok.Lombok;
|
||||
import lombok.core.DiagnosticsReceiver;
|
||||
@@ -48,6 +52,7 @@ import lombok.javac.JavacTransformer;
|
||||
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.Trees;
|
||||
import com.sun.tools.javac.processing.JavacFiler;
|
||||
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
@@ -74,12 +79,12 @@ public class Processor extends AbstractProcessor {
|
||||
@Override public void init(ProcessingEnvironment procEnv) {
|
||||
super.init(procEnv);
|
||||
this.processingEnv = (JavacProcessingEnvironment) procEnv;
|
||||
placePostCompileHook();
|
||||
placePostCompileAndDontMakeForceRoundDummiesHook();
|
||||
transformer = new JavacTransformer(procEnv.getMessager());
|
||||
trees = Trees.instance(procEnv);
|
||||
}
|
||||
|
||||
private void placePostCompileHook() {
|
||||
private void placePostCompileAndDontMakeForceRoundDummiesHook() {
|
||||
stopJavacProcessingEnvironmentFromClosingOurClassloader();
|
||||
|
||||
Context context = processingEnv.getContext();
|
||||
@@ -100,6 +105,9 @@ public class Processor extends AbstractProcessor {
|
||||
|
||||
JavaFileManager newFiler = new InterceptingJavaFileManager(originalFiler, receiver);
|
||||
ht.put(key, newFiler);
|
||||
Field filerFileManagerField = JavacFiler.class.getDeclaredField("fileManager");
|
||||
filerFileManagerField.setAccessible(true);
|
||||
filerFileManagerField.set(processingEnv.getFiler(), newFiler);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
@@ -164,15 +172,43 @@ public class Processor extends AbstractProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private final IdentityHashMap<JCCompilationUnit, Void> rootsAtPhase0 = new IdentityHashMap<JCCompilationUnit, Void>();
|
||||
private final IdentityHashMap<JCCompilationUnit, Void> rootsAtPhase1 = new IdentityHashMap<JCCompilationUnit, Void>();
|
||||
private int dummyCount = 0;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
IdentityHashMap<JCCompilationUnit, Void> units = new IdentityHashMap<JCCompilationUnit, Void>();
|
||||
for (Element element : roundEnv.getRootElements()) {
|
||||
JCCompilationUnit unit = toUnit(element);
|
||||
if (unit != null) units.put(unit, null);
|
||||
if (roundEnv.processingOver()) return false;
|
||||
|
||||
if (!rootsAtPhase0.isEmpty()) {
|
||||
ArrayList<JCCompilationUnit> cus = new ArrayList<JCCompilationUnit>(rootsAtPhase0.keySet());
|
||||
transformer.transform(true, processingEnv.getContext(), cus);
|
||||
rootsAtPhase1.putAll(rootsAtPhase0);
|
||||
rootsAtPhase0.clear();
|
||||
}
|
||||
|
||||
transformer.transform(processingEnv.getContext(), units.keySet());
|
||||
for (Element element : roundEnv.getRootElements()) {
|
||||
JCCompilationUnit unit = toUnit(element);
|
||||
if (unit != null) {
|
||||
if (!rootsAtPhase1.containsKey(unit)) rootsAtPhase0.put(unit, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rootsAtPhase0.isEmpty()) {
|
||||
ArrayList<JCCompilationUnit> cus = new ArrayList<JCCompilationUnit>(rootsAtPhase0.keySet());
|
||||
transformer.transform(false, processingEnv.getContext(), cus);
|
||||
JavacFiler filer = (JavacFiler) processingEnv.getFiler();
|
||||
if (!filer.newFiles()) {
|
||||
try {
|
||||
JavaFileObject dummy = filer.createSourceFile("lombok.dummy.ForceNewRound" + (dummyCount++));
|
||||
Writer w = dummy.openWriter();
|
||||
w.close();
|
||||
} catch (Exception e) {
|
||||
processingEnv.getMessager().printMessage(Kind.WARNING,
|
||||
"Can't force a new processing round. Lombok features that require resolution won't work.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -156,4 +156,8 @@ public class HandleCleanup implements JavacAnnotationHandler<Cleanup> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,10 @@ public class HandleConstructor {
|
||||
new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
@@ -86,6 +90,10 @@ public class HandleConstructor {
|
||||
new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, false, suppressConstructorProperties);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<JavacNode> findRequiredFields(JavacNode typeNode) {
|
||||
@@ -131,6 +139,10 @@ public class HandleConstructor {
|
||||
new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, suppressConstructorProperties);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists) {
|
||||
|
||||
@@ -65,4 +65,8 @@ public class HandleData implements JavacAnnotationHandler<Data> {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -481,4 +481,8 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
|
||||
private JCStatement returnBool(TreeMaker maker, boolean bool) {
|
||||
return maker.Return(maker.Literal(TypeTags.BOOLEAN, bool ? 1 : 0));
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -208,4 +208,8 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
|
||||
return treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType,
|
||||
methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue);
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -121,6 +121,10 @@ public class HandleLog {
|
||||
@Override public boolean handle(AnnotationValues<lombok.extern.apachecommons.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
return processAnnotation(LoggingFramework.COMMONS, annotation, annotationNode);
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +135,11 @@ public class HandleLog {
|
||||
@Override public boolean handle(AnnotationValues<lombok.extern.jul.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
return processAnnotation(LoggingFramework.JUL, annotation, annotationNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the {@link lombok.extern.log4j.Log} annotation for javac.
|
||||
@@ -141,6 +149,10 @@ public class HandleLog {
|
||||
@Override public boolean handle(AnnotationValues<lombok.extern.log4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
return processAnnotation(LoggingFramework.LOG4J, annotation, annotationNode);
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,6 +163,10 @@ public class HandleLog {
|
||||
@Override public boolean handle(AnnotationValues<lombok.extern.slf4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
return processAnnotation(LoggingFramework.SLF4J, annotation, annotationNode);
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum LoggingFramework {
|
||||
|
||||
@@ -54,4 +54,8 @@ public class HandlePrintAST implements JavacAnnotationHandler<PrintAST> {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -249,4 +249,8 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> {
|
||||
return v.visitNoType(this, p);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -110,4 +110,8 @@ public class HandleSneakyThrows implements JavacAnnotationHandler<SneakyThrows>
|
||||
|
||||
return maker.Try(tryBlock, List.of(maker.Catch(catchParam, catchBody)), null);
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -107,4 +107,8 @@ public class HandleSynchronized implements JavacAnnotationHandler<Synchronized>
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -247,4 +247,8 @@ public class HandleToString implements JavacAnnotationHandler<ToString> {
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
|
||||
@Override public boolean isResolutionBased() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2010 Reinier Zwitserloot and Roel Spilker.
|
||||
* Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -41,16 +41,11 @@ import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.DiagnosticListener;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
|
||||
import lombok.javac.DeleteLombokAnnotations;
|
||||
import lombok.javac.JavacTransformer;
|
||||
import lombok.javac.TrackChangedAsts;
|
||||
|
||||
import com.sun.tools.javac.main.JavaCompiler;
|
||||
import com.sun.tools.javac.main.OptionName;
|
||||
@@ -358,6 +353,7 @@ public class Delombok {
|
||||
options.put(OptionName.ENCODING, charset.name());
|
||||
if (classpath != null) options.put(OptionName.CLASSPATH, classpath);
|
||||
if (sourcepath != null) options.put(OptionName.SOURCEPATH, sourcepath);
|
||||
options.put("compilePolicy", "attr");
|
||||
CommentCollectingScanner.Factory.preRegister(context);
|
||||
|
||||
JavaCompiler compiler = new JavaCompiler(context);
|
||||
@@ -367,6 +363,9 @@ public class Delombok {
|
||||
List<JCCompilationUnit> roots = new ArrayList<JCCompilationUnit>();
|
||||
Map<JCCompilationUnit, Comments> commentsMap = new IdentityHashMap<JCCompilationUnit, Comments>();
|
||||
Map<JCCompilationUnit, File> baseMap = new IdentityHashMap<JCCompilationUnit, File>();
|
||||
|
||||
compiler.initProcessAnnotations(Collections.singleton(new lombok.javac.apt.Processor()));
|
||||
|
||||
for (File fileToParse : filesToParse) {
|
||||
Comments comments = new Comments();
|
||||
context.put(Comments.class, comments);
|
||||
@@ -379,12 +378,18 @@ public class Delombok {
|
||||
roots.add(unit);
|
||||
}
|
||||
|
||||
if (compiler.errorCount() > 0) return false;
|
||||
compiler.enterTrees(toJavacList(roots));
|
||||
if (compiler.errorCount() > 0) {
|
||||
// At least one parse error. No point continuing (a real javac run doesn't either).
|
||||
return false;
|
||||
}
|
||||
|
||||
TrackChangedAsts tca = new TrackChangedAsts();
|
||||
|
||||
context.put(TrackChangedAsts.class, tca);
|
||||
|
||||
JavaCompiler delegate = compiler.processAnnotations(compiler.enterTrees(toJavacList(roots)));
|
||||
for (JCCompilationUnit unit : roots) {
|
||||
boolean changed = new JavacTransformer(messager).transform(context, Collections.singleton(unit));
|
||||
DelombokResult result = new DelombokResult(commentsMap.get(unit).comments, unit, force || changed);
|
||||
DelombokResult result = new DelombokResult(commentsMap.get(unit).comments, unit, force || tca.changed.contains(unit));
|
||||
if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged");
|
||||
Writer rawWriter;
|
||||
if (presetWriter != null) rawWriter = presetWriter;
|
||||
@@ -397,6 +402,7 @@ public class Delombok {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
delegate.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -409,24 +415,6 @@ public class Delombok {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Messager messager = new Messager() {
|
||||
@Override public void printMessage(Kind kind, CharSequence msg) {
|
||||
System.out.printf("%s: %s\n", kind, msg);
|
||||
}
|
||||
|
||||
@Override public void printMessage(Kind kind, CharSequence msg, Element e) {
|
||||
System.out.printf("%s: %s\n", kind, msg);
|
||||
}
|
||||
|
||||
@Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) {
|
||||
System.out.printf("%s: %s\n", kind, msg);
|
||||
}
|
||||
|
||||
@Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) {
|
||||
System.out.printf("%s: %s\n", kind, msg);
|
||||
}
|
||||
};
|
||||
|
||||
private static String canonical(File dir) {
|
||||
try {
|
||||
return dir.getCanonicalPath();
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
|
||||
*
|
||||
* 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.installer.netbeans;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.installer.CorruptedIdeLocationException;
|
||||
import lombok.installer.IdeFinder;
|
||||
import lombok.installer.IdeLocation;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
/** Utility class for doing various OS-specific operations related to finding Netbeans installations. */
|
||||
@ProviderFor(IdeFinder.class)
|
||||
public class NetbeansFinder extends IdeFinder {
|
||||
/**
|
||||
* Returns a list of paths of Netbeans installations.
|
||||
*
|
||||
* Netbeans installations are found by checking for the existence of 'netbeans.exe' in the following locations:
|
||||
* <ul>
|
||||
* <li>X:\*Program Files*\*NetBeans*</li>
|
||||
* <li>X:\*NetBeans*</li>
|
||||
* </ul>
|
||||
*
|
||||
* Where 'X' is tried for all local disk drives, unless there's a problem calling fsutil, in which case only
|
||||
* C: is tried.
|
||||
*/
|
||||
private void findNetbeansOnWindows(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
|
||||
List<String> driveLetters = asList("C");
|
||||
try {
|
||||
driveLetters = getDrivesOnWindows();
|
||||
} catch (Throwable ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
|
||||
//Various try/catch/ignore statements are in this for loop. Weird conditions on the disk can cause exceptions,
|
||||
//such as an unformatted drive causing a NullPointerException on listFiles. Best action is almost invariably to just
|
||||
//continue onwards.
|
||||
for (String letter : driveLetters) {
|
||||
try {
|
||||
File f = new File(letter + ":\\");
|
||||
for (File dir : f.listFiles()) {
|
||||
if (!dir.isDirectory()) continue;
|
||||
try {
|
||||
if (dir.getName().toLowerCase().contains("netbeans")) {
|
||||
String netbeansLocation = findNetbeansOnWindows1(dir);
|
||||
if (netbeansLocation != null) {
|
||||
try {
|
||||
IdeLocation newLocation = NetbeansLocationProvider.create0(netbeansLocation);
|
||||
if (newLocation != null) locations.add(newLocation);
|
||||
} catch (CorruptedIdeLocationException e) {
|
||||
problems.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
|
||||
try {
|
||||
if (dir.getName().toLowerCase().contains("program files")) {
|
||||
for (File dir2 : dir.listFiles()) {
|
||||
if (!dir2.isDirectory()) continue;
|
||||
if (dir2.getName().toLowerCase().contains("netbeans")) {
|
||||
String netbeansLocation = findNetbeansOnWindows1(dir2);
|
||||
if (netbeansLocation != null) {
|
||||
try {
|
||||
IdeLocation newLocation = NetbeansLocationProvider.create0(netbeansLocation);
|
||||
if (newLocation != null) locations.add(newLocation);
|
||||
} catch (CorruptedIdeLocationException e) {
|
||||
problems.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks if the provided directory contains 'netbeans.exe', and if so, returns the directory, otherwise null. */
|
||||
private String findNetbeansOnWindows1(File dir) {
|
||||
if (new File(dir, "bin/netbeans.exe").isFile()) return dir.getAbsolutePath();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the OS-dependent 'find Netbeans' routine. If the local OS doesn't have a routine written for it,
|
||||
* null is returned.
|
||||
*
|
||||
* @param locations
|
||||
* List of valid netbeans locations - provide an empty list; this
|
||||
* method will fill it.
|
||||
* @param problems
|
||||
* List of netbeans locations that seem to contain half-baked
|
||||
* netbeanses that can't be installed. Provide an empty list; this
|
||||
* method will fill it.
|
||||
*/
|
||||
@Override
|
||||
public void findIdes(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
|
||||
switch (getOS()) {
|
||||
case WINDOWS:
|
||||
findNetbeansOnWindows(locations, problems);
|
||||
break;
|
||||
case MAC_OS_X:
|
||||
findNetbeansOnMac(locations, problems);
|
||||
break;
|
||||
default:
|
||||
case UNIX:
|
||||
findNetbeansOnUnix(locations, problems);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Scans a couple of likely locations on linux. */
|
||||
private void findNetbeansOnUnix(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
|
||||
List<String> guesses = new ArrayList<String>();
|
||||
|
||||
File d;
|
||||
|
||||
d = new File("/usr/bin/netbeans");
|
||||
if (d.exists()) guesses.add(d.getPath());
|
||||
d = new File("/usr/local/bin/netbeans");
|
||||
if (d.exists()) guesses.add(d.getPath());
|
||||
d = new File(System.getProperty("user.home", "."), "bin/netbeans");
|
||||
if (d.exists()) guesses.add(d.getPath());
|
||||
|
||||
findNetbeansInSubDir("/usr/local/share", guesses);
|
||||
findNetbeansInSubDir("/usr/local", guesses);
|
||||
findNetbeansInSubDir("/usr/share", guesses);
|
||||
findNetbeansInSubDir(System.getProperty("user.home", "."), guesses);
|
||||
|
||||
for (String guess : guesses) {
|
||||
try {
|
||||
IdeLocation newLocation = NetbeansLocationProvider.create0(guess);
|
||||
if (newLocation != null) locations.add(newLocation);
|
||||
} catch (CorruptedIdeLocationException e) {
|
||||
problems.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void findNetbeansInSubDir(String dir, List<String> guesses) {
|
||||
File d = new File(dir);
|
||||
if (!d.isDirectory()) return;
|
||||
for (File f : d.listFiles()) {
|
||||
if (f.isDirectory() && f.getName().toLowerCase().contains("netbeans")) {
|
||||
File possible = new File(f, "bin/netbeans");
|
||||
if (possible.exists()) guesses.add(possible.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans /Applications for any folder named 'Eclipse'
|
||||
*/
|
||||
private static void findNetbeansOnMac(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
|
||||
for (File dir : new File("/Applications").listFiles()) {
|
||||
if (!dir.isDirectory()) continue;
|
||||
if (dir.getName().toLowerCase().startsWith("netbeans") && dir.getName().toLowerCase().endsWith(".app")) {
|
||||
try {
|
||||
IdeLocation newLocation = NetbeansLocationProvider.create0(dir.getAbsolutePath());
|
||||
if (newLocation != null) locations.add(newLocation);
|
||||
} catch (CorruptedIdeLocationException e) {
|
||||
problems.add(e);
|
||||
}
|
||||
}
|
||||
if (dir.getName().toLowerCase().contains("netbeans")) {
|
||||
for (File dir2 : dir.listFiles()) {
|
||||
if (!dir2.isDirectory()) continue;
|
||||
if (dir2.getName().toLowerCase().startsWith("netbeans") && dir2.getName().toLowerCase().endsWith(".app")) {
|
||||
try {
|
||||
IdeLocation newLocation = NetbeansLocationProvider.create0(dir2.getAbsolutePath());
|
||||
if (newLocation != null) locations.add(newLocation);
|
||||
} catch (CorruptedIdeLocationException e) {
|
||||
problems.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker.
|
||||
*
|
||||
* 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.installer.netbeans;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import lombok.installer.CorruptedIdeLocationException;
|
||||
import lombok.installer.IdeFinder;
|
||||
import lombok.installer.IdeLocation;
|
||||
import lombok.installer.InstallException;
|
||||
import lombok.installer.Installer;
|
||||
import lombok.installer.UninstallException;
|
||||
|
||||
public class NetbeansLocation extends IdeLocation {
|
||||
private final String name;
|
||||
private final File netbeansConfPath;
|
||||
private final String version;
|
||||
private final int versionFirst, versionSecond;
|
||||
private final boolean hasLombok;
|
||||
|
||||
private static final String OS_NEWLINE = IdeFinder.getOS().getLineEnding();
|
||||
|
||||
NetbeansLocation(String nameOfLocation, File pathToNetbeansConf) throws CorruptedIdeLocationException {
|
||||
this.name = nameOfLocation;
|
||||
this.netbeansConfPath = pathToNetbeansConf;
|
||||
try {
|
||||
this.hasLombok = checkForLombok(netbeansConfPath);
|
||||
} catch (IOException e) {
|
||||
throw new CorruptedIdeLocationException(
|
||||
"I can't read the configuration file of the Netbeans installed at " + name + "\n" +
|
||||
"You may need to run this installer with root privileges if you want to modify that Netbeans.", "netbeans", e);
|
||||
}
|
||||
this.version = findNetbeansVersion(netbeansConfPath);
|
||||
int first, second;
|
||||
String[] vs = version.split("\\.");
|
||||
try {
|
||||
first = Integer.parseInt(vs[0]);
|
||||
} catch (Exception e) {
|
||||
first = 0;
|
||||
}
|
||||
try {
|
||||
second = Integer.parseInt(vs[1]);
|
||||
} catch (Exception e) {
|
||||
second = 0;
|
||||
}
|
||||
this.versionFirst = first;
|
||||
this.versionSecond = second;
|
||||
}
|
||||
|
||||
public boolean versionIsPre68() {
|
||||
return versionFirst < 6 || (versionFirst == 6 && versionSecond < 8);
|
||||
}
|
||||
|
||||
public boolean versionIs68() {
|
||||
return versionFirst == 6 && versionSecond == 8;
|
||||
}
|
||||
|
||||
public boolean versionIsPost68() {
|
||||
return versionFirst > 6 || (versionFirst == 6 && versionSecond > 8);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return netbeansConfPath.hashCode();
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
if (!(o instanceof NetbeansLocation)) return false;
|
||||
return ((NetbeansLocation)o).netbeansConfPath.equals(netbeansConfPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this location; generally the path to the netbeans executable.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the Netbeans installation has been instrumented with lombok.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasLombok() {
|
||||
return hasLombok;
|
||||
}
|
||||
|
||||
private final String ID_CHARS = "(?:\\\\.|[^\"\\\\])*";
|
||||
private final Pattern JAVA_AGENT_LINE_MATCHER = Pattern.compile(
|
||||
"^\\s*netbeans_default_options\\s*=\\s*\"\\s*" + ID_CHARS + "(?<=[ \"])(-J-javaagent:\\\\\".*lombok.*\\.jar\\\\\")(?=[ \"])" + ID_CHARS +"\\s*\"\\s*(?:#.*)?$", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private final Pattern OPTIONS_LINE_MATCHER = Pattern.compile(
|
||||
"^\\s*netbeans_default_options\\s*=\\s*\"\\s*" + ID_CHARS + "\\s*(\")\\s*(?:#.*)?$", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private String findNetbeansVersion(File iniFile) {
|
||||
String forcedVersion = System.getProperty("force.netbeans.version", null);
|
||||
if (forcedVersion != null) return forcedVersion;
|
||||
|
||||
try {
|
||||
for (File child : iniFile.getParentFile().getParentFile().listFiles()) {
|
||||
if (!child.isDirectory()) continue;
|
||||
String name = child.getName();
|
||||
if (name == null || !name.startsWith("nb")) continue;
|
||||
String version = name.substring(2);
|
||||
File versionFile = new File(child, "VERSION.txt");
|
||||
if (versionFile.exists() && versionFile.canRead() && !versionFile.isDirectory()) {
|
||||
try {
|
||||
version = readVersionFile(versionFile);
|
||||
} catch (IOException e) {
|
||||
// Intentional Fallthrough
|
||||
}
|
||||
}
|
||||
if (version != null && version.length() > 0) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
// Intentional Fallthrough
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
private static String readVersionFile(File file) throws IOException {
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
StringBuilder version = new StringBuilder();
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
|
||||
for (String line = br.readLine(); line != null; line = br.readLine()) {
|
||||
if (line.startsWith("#")) continue;
|
||||
if (version.length() > 0) version.append(" ");
|
||||
version.append(line);
|
||||
}
|
||||
return version.toString();
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkForLombok(File iniFile) throws IOException {
|
||||
if (!iniFile.exists()) return false;
|
||||
FileInputStream fis = new FileInputStream(iniFile);
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (JAVA_AGENT_LINE_MATCHER.matcher(line.trim()).matches()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls lombok from this location.
|
||||
* It's a no-op if lombok wasn't there in the first place,
|
||||
* and it will remove a half-succeeded lombok installation as well.
|
||||
*
|
||||
* @throws UninstallException
|
||||
* If there's an obvious I/O problem that is preventing
|
||||
* installation. bugs in the uninstall code will probably throw
|
||||
* other exceptions; this is intentional.
|
||||
*/
|
||||
@Override
|
||||
public void uninstall() throws UninstallException {
|
||||
final List<File> lombokJarsForWhichCantDeleteSelf = new ArrayList<File>();
|
||||
File dir = netbeansConfPath.getParentFile();
|
||||
|
||||
StringBuilder newContents = new StringBuilder();
|
||||
if (netbeansConfPath.exists()) {
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(netbeansConfPath);
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Matcher m = JAVA_AGENT_LINE_MATCHER.matcher(line);
|
||||
if (m.matches()) {
|
||||
newContents.append(line.substring(0, m.start(1)) + line.substring(m.end(1)));
|
||||
} else {
|
||||
newContents.append(line);
|
||||
}
|
||||
newContents.append(OS_NEWLINE);
|
||||
}
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(netbeansConfPath);
|
||||
try {
|
||||
fos.write(newContents.toString().getBytes());
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UninstallException("Cannot uninstall lombok from " + name + generateWriteErrorMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
File lombokJar = new File(dir, "lombok.jar");
|
||||
if (lombokJar.exists()) {
|
||||
if (!lombokJar.delete()) {
|
||||
if (IdeFinder.getOS() == IdeFinder.OS.WINDOWS && Installer.isSelf(lombokJar.getAbsolutePath())) {
|
||||
lombokJarsForWhichCantDeleteSelf.add(lombokJar);
|
||||
} else {
|
||||
throw new UninstallException(
|
||||
"Can't delete " + lombokJar.getAbsolutePath() + generateWriteErrorMessage(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!lombokJarsForWhichCantDeleteSelf.isEmpty()) {
|
||||
throw new UninstallException(true,
|
||||
"lombok.jar cannot delete itself on windows.\nHowever, lombok has been uncoupled from your netbeans.\n" +
|
||||
"You can safely delete this jar file. You can find it at:\n" +
|
||||
lombokJarsForWhichCantDeleteSelf.get(0).getAbsolutePath(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateWriteErrorMessage() {
|
||||
String osSpecificError;
|
||||
|
||||
switch (IdeFinder.getOS()) {
|
||||
default:
|
||||
case MAC_OS_X:
|
||||
case UNIX:
|
||||
osSpecificError = ":\nStart terminal, go to the directory with lombok.jar, and run: sudo java -jar lombok.jar";
|
||||
break;
|
||||
case WINDOWS:
|
||||
osSpecificError = ":\nStart a new cmd (dos box) with admin privileges, go to the directory with lombok.jar, and run: java -jar lombok.jar";
|
||||
break;
|
||||
}
|
||||
|
||||
return ", probably because this installer does not have the access rights.\n" +
|
||||
"Try re-running the installer with administrative privileges" + osSpecificError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install lombok into the Netbeans at this location.
|
||||
* If lombok is already there, it is overwritten neatly (upgrade mode).
|
||||
*
|
||||
* @throws InstallException
|
||||
* If there's an obvious I/O problem that is preventing
|
||||
* installation. bugs in the install code will probably throw
|
||||
* other exceptions; this is intentional.
|
||||
*/
|
||||
@Override
|
||||
public String install() throws InstallException {
|
||||
if ("UNKNOWN".equals(version)) {
|
||||
throw new InstallException(String.format(
|
||||
"Can't determine version of Netbeans installed at:\n%s\n\n" +
|
||||
"Your Netbeans version determines what this installer does:\n" +
|
||||
"Pre 6.8: Lombok is not compatible with netbeans pre 6.8, and thus won't install.\n" +
|
||||
"6.8: Lombok will install itself into Netbeans.\n" +
|
||||
"6.9 and later: NetBeans supports lombok natively. This installer will explain how to enable it.\n\n" +
|
||||
"If you know your netbeans version, you can force this by starting the installer with:\n" +
|
||||
"java -Dforce.netbeans.version=6.8 -jar lombok.jar", this.getName()), null);
|
||||
}
|
||||
|
||||
if (versionIsPre68()) {
|
||||
throw new InstallException(String.format(
|
||||
"Lombok is not compatible with Netbeans versions prior to 6.8.\n" +
|
||||
"Therefore, lombok will not be installed at:\n%s\nbecause it is version: %s",
|
||||
this.getName(), version), null);
|
||||
}
|
||||
if (versionIsPost68()) {
|
||||
try {
|
||||
uninstall();
|
||||
} catch (Exception e) {
|
||||
// Well, we tried. Lombok on 6.9 doesn't do anything, so we'll leave it then.
|
||||
}
|
||||
|
||||
throw new InstallException(true, String.format(
|
||||
"Starting with NetBeans 6.9, lombok is natively supported and does not need to be installed at:\n%s\n\n" +
|
||||
"To use lombok.jar in your netbeans project:\n" +
|
||||
"1. Add lombok.jar to your project (Go to Project Properties, 'Libraries' page, and add lombok.jar in the 'Compile' tab).\n" +
|
||||
"2. Enable Annotation Processors (Go to Project Properties, 'Build/Compiling' page, and check 'Enable Annotation Processing in Editor').\n" +
|
||||
"\n" +
|
||||
"NB: In the first release of NetBeans 6.9, due to a netbeans bug, maven-based projects don't run annotation processors. This \n" +
|
||||
"issue should be fixed by the great folks at NetBeans soon.", this.getName()), null);
|
||||
}
|
||||
|
||||
boolean installSucceeded = false;
|
||||
StringBuilder newContents = new StringBuilder();
|
||||
|
||||
File lombokJar = new File(netbeansConfPath.getParentFile(), "lombok.jar");
|
||||
|
||||
/* No need to copy lombok.jar to itself, obviously. On windows this would generate an error so we check for this. */
|
||||
if (!Installer.isSelf(lombokJar.getAbsolutePath())) {
|
||||
File ourJar = findOurJar();
|
||||
byte[] b = new byte[524288];
|
||||
boolean readSucceeded = true;
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(lombokJar);
|
||||
try {
|
||||
readSucceeded = false;
|
||||
InputStream in = new FileInputStream(ourJar);
|
||||
try {
|
||||
while (true) {
|
||||
int r = in.read(b);
|
||||
if (r == -1) break;
|
||||
if (r > 0) readSucceeded = true;
|
||||
out.write(b, 0, r);
|
||||
}
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
lombokJar.delete();
|
||||
} catch (Throwable ignore) { /* Nothing we can do about that. */ }
|
||||
if (!readSucceeded) throw new InstallException(
|
||||
"I can't read my own jar file. I think you've found a bug in this installer!\nI suggest you restart it " +
|
||||
"and use the 'what do I do' link, to manually install lombok. Also, tell us about this at:\n" +
|
||||
"http://groups.google.com/group/project-lombok - Thanks!", e);
|
||||
throw new InstallException("I can't write to your Netbeans directory at " + name + generateWriteErrorMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(netbeansConfPath);
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Matcher m = JAVA_AGENT_LINE_MATCHER.matcher(line);
|
||||
if (m.matches()) {
|
||||
newContents.append(line.substring(0, m.start(1)));
|
||||
newContents.append("-J-javaagent:\\\"" + canonical(lombokJar) + "\\\"");
|
||||
newContents.append(line.substring(m.end(1)));
|
||||
newContents.append(OS_NEWLINE);
|
||||
continue;
|
||||
}
|
||||
|
||||
m = OPTIONS_LINE_MATCHER.matcher(line);
|
||||
if (m.matches()) {
|
||||
newContents.append(line.substring(0, m.start(1)));
|
||||
newContents.append(" ").append("-J-javaagent:\\\"" + canonical(lombokJar) +"\\\"\"");
|
||||
newContents.append(line.substring(m.end(1))).append(OS_NEWLINE);
|
||||
continue;
|
||||
}
|
||||
|
||||
newContents.append(line).append(OS_NEWLINE);
|
||||
}
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(netbeansConfPath);
|
||||
try {
|
||||
fos.write(newContents.toString().getBytes());
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
installSucceeded = true;
|
||||
} catch (IOException e) {
|
||||
throw new InstallException("Cannot install lombok at " + name + generateWriteErrorMessage(), e);
|
||||
} finally {
|
||||
if (!installSucceeded) try {
|
||||
lombokJar.delete();
|
||||
} catch (Throwable ignore) {}
|
||||
}
|
||||
|
||||
if (!installSucceeded) {
|
||||
throw new InstallException("I can't find the netbeans.conf file. Is this a real Netbeans installation?", null);
|
||||
}
|
||||
|
||||
return "If you start netbeans with custom parameters, you'll need to add:<br>" +
|
||||
"<code>-J-javaagent:\\\"" + canonical(lombokJar) + "\\\"</code><br>" +
|
||||
"as parameter as well.";
|
||||
}
|
||||
|
||||
@Override public URL getIdeIcon() {
|
||||
return NetbeansLocation.class.getResource("netbeans.png");
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
|
||||
*
|
||||
* 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.installer.netbeans;
|
||||
|
||||
import static lombok.installer.IdeLocation.canonical;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import lombok.installer.CorruptedIdeLocationException;
|
||||
import lombok.installer.IdeLocation;
|
||||
import lombok.installer.IdeLocationProvider;
|
||||
import lombok.installer.IdeFinder.OS;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
@ProviderFor(IdeLocationProvider.class)
|
||||
public class NetbeansLocationProvider implements IdeLocationProvider {
|
||||
|
||||
@Override public IdeLocation create(String path) throws CorruptedIdeLocationException {
|
||||
return create0(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NetbeansLocation by pointing at either the directory containing the executable, or the executable itself,
|
||||
* or a netbeans.conf file.
|
||||
*
|
||||
* @throws NotAnIdeLocationException
|
||||
* If this isn't an Eclipse executable or a directory with an
|
||||
* Eclipse executable.
|
||||
*/
|
||||
static NetbeansLocation create0(String path) throws CorruptedIdeLocationException {
|
||||
if (path == null) throw new NullPointerException("path");
|
||||
File p = new File(path);
|
||||
|
||||
if (!p.exists()) return null;
|
||||
if (p.isDirectory()) {
|
||||
String name = p.getName().toLowerCase();
|
||||
if (name.endsWith(".app") && name.startsWith("netbeans")) {
|
||||
File conf = new File(p, "Contents/Resources/NetBeans/etc/netbeans.conf");
|
||||
if (conf.exists()) return new NetbeansLocation(path, conf);
|
||||
}
|
||||
|
||||
File f = new File(p, "bin/netbeans");
|
||||
if (f.isFile()) return findNetbeansConfFromExe(f, 0);
|
||||
f = new File(p, "bin/netbeans.exe");
|
||||
if (f.isFile()) return findNetbeansConfFromExe(f, 0);
|
||||
f = new File(p, "etc/netbeans.conf");
|
||||
if (f.isFile()) return new NetbeansLocation(canonical(f.getParentFile().getParentFile()), f);
|
||||
}
|
||||
|
||||
if (p.isFile()) {
|
||||
if (p.getName().equalsIgnoreCase("netbeans.conf")) {
|
||||
return new NetbeansLocation(canonical(p.getParentFile().getParentFile()), p);
|
||||
}
|
||||
|
||||
if (p.getName().equalsIgnoreCase("netbeans") || p.getName().equalsIgnoreCase("netbeans.exe")) {
|
||||
return findNetbeansConfFromExe(p, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static NetbeansLocation findNetbeansConfFromExe(File exePath, int loopCounter) throws CorruptedIdeLocationException {
|
||||
/* Try looking for netbeans.conf as etc/netbeans.conf */ {
|
||||
File conf = new File(exePath.getParentFile(), "etc/netbeans.conf");
|
||||
if (conf.isFile()) return new NetbeansLocation(canonical(exePath), conf);
|
||||
}
|
||||
|
||||
/* Try looking for netbeans.conf as ../etc/netbeans.conf */ {
|
||||
File conf = new File(exePath.getParentFile().getParentFile(), "etc/netbeans.conf");
|
||||
if (conf.isFile()) return new NetbeansLocation(canonical(exePath), conf);
|
||||
}
|
||||
|
||||
/* If executable is a soft link, follow it and retry. */ {
|
||||
if (loopCounter < 50) {
|
||||
try {
|
||||
String oPath = exePath.getAbsolutePath();
|
||||
String nPath = exePath.getCanonicalPath();
|
||||
if (!oPath.equals(nPath)) try {
|
||||
return findNetbeansConfFromExe(new File(nPath), loopCounter + 1);
|
||||
} catch (CorruptedIdeLocationException ignore) {
|
||||
// Unlinking didn't help find a netbeans, so continue.
|
||||
}
|
||||
} catch (IOException ignore) { /* okay, that didn't work, assume it isn't a soft link then. */ }
|
||||
}
|
||||
}
|
||||
|
||||
/* If we get this far, we lose. */
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public Pattern getLocationSelectors(OS os) {
|
||||
switch (os) {
|
||||
case MAC_OS_X:
|
||||
return Pattern.compile("^(netbeans|netbeans\\.conf|NetBeans.*\\.app)$", Pattern.CASE_INSENSITIVE);
|
||||
case WINDOWS:
|
||||
return Pattern.compile("^(netbeans\\.exe|netbeans\\.conf)$", Pattern.CASE_INSENSITIVE);
|
||||
default:
|
||||
case UNIX:
|
||||
return Pattern.compile("^(netbeans|netbeans\\.conf)$", Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
|
||||
*
|
||||
* 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.netbeans.agent;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
|
||||
import lombok.javac.JavacTransformer;
|
||||
|
||||
import com.sun.source.util.TaskEvent;
|
||||
import com.sun.source.util.TaskListener;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
|
||||
public class NetbeansEntryPoint implements TaskListener {
|
||||
public class DummyMessager implements Messager {
|
||||
@Override public void printMessage(Kind kind, CharSequence msg) {
|
||||
System.err.printf("%s: %s\n", kind, msg);
|
||||
}
|
||||
|
||||
@Override public void printMessage(Kind kind, CharSequence msg, Element e) {
|
||||
printMessage(kind, msg);
|
||||
}
|
||||
|
||||
@Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) {
|
||||
printMessage(kind, msg);
|
||||
}
|
||||
|
||||
@Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) {
|
||||
printMessage(kind, msg);
|
||||
}
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
|
||||
public NetbeansEntryPoint(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override public void started(TaskEvent event) {
|
||||
//we run at the end, so all the action is in #finished.
|
||||
}
|
||||
|
||||
@Override public void finished(TaskEvent event) {
|
||||
if (TaskEvent.Kind.PARSE == event.getKind()) {
|
||||
JavacTransformer transformer = new JavacTransformer(new DummyMessager()); //TODO hook into netbeans error reporting!
|
||||
JCCompilationUnit compilationUnit = (JCCompilationUnit) event.getCompilationUnit();
|
||||
transformer.transform(context, Collections.singleton(compilationUnit));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
|
||||
*
|
||||
* 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.netbeans.agent;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
|
||||
import lombok.core.Agent;
|
||||
import lombok.patcher.Hook;
|
||||
import lombok.patcher.MethodTarget;
|
||||
import lombok.patcher.ScriptManager;
|
||||
import lombok.patcher.StackRequest;
|
||||
import lombok.patcher.scripts.ScriptBuilder;
|
||||
|
||||
/**
|
||||
* This is a java-agent that patches some of netbeans's classes so that lombok is initialized as Javac TaskListener,
|
||||
* allowing us to change AST nodes anytime netbeans parses source code. It also fixes some of the places in netbeans that
|
||||
* can't deal with generated code.
|
||||
*
|
||||
* The hard work on figuring out where to patch has been done by Jan Lahoda (jlahoda@netbeans.org)
|
||||
*/
|
||||
public class NetbeansPatcher extends Agent {
|
||||
@Override
|
||||
public void runAgent(String agentArgs, Instrumentation instrumentation, boolean injected) throws Exception {
|
||||
registerPatchScripts(instrumentation, injected);
|
||||
}
|
||||
|
||||
private static void registerPatchScripts(Instrumentation instrumentation, boolean reloadExistingClasses) {
|
||||
ScriptManager sm = new ScriptManager();
|
||||
sm.registerTransformer(instrumentation);
|
||||
|
||||
patchNetbeansClassLoader(sm);
|
||||
patchNetbeansJavac(sm);
|
||||
patchNetbeansMissingPositionAwareness(sm);
|
||||
|
||||
if (reloadExistingClasses) sm.reloadClasses(instrumentation);
|
||||
}
|
||||
|
||||
private static void patchNetbeansClassLoader(ScriptManager sm) {
|
||||
sm.addScript(ScriptBuilder.exitEarly()
|
||||
.transplant().request(StackRequest.PARAM1, StackRequest.PARAM2)
|
||||
.target(new MethodTarget("org.netbeans.StandardModule$OneModuleClassLoader", "<init>"))
|
||||
.decisionMethod(new Hook("lombok.netbeans.agent.PatchFixes", "addSelfToClassLoader", "void", "org.netbeans.Module", "java.util.List"))
|
||||
.build());
|
||||
sm.addScript(ScriptBuilder.exitEarly()
|
||||
.transplant()
|
||||
.request(StackRequest.THIS, StackRequest.PARAM1)
|
||||
.target(new MethodTarget("org.netbeans.ProxyClassLoader", "getResource"))
|
||||
.decisionMethod(new Hook("lombok.netbeans.agent.PatchFixes", "getResource_decision", "boolean", "java.lang.ClassLoader", "java.lang.String"))
|
||||
.valueMethod(new Hook("lombok.netbeans.agent.PatchFixes", "getResource_value", "java.net.URL", "java.lang.ClassLoader", "java.lang.String"))
|
||||
.build());
|
||||
sm.addScript(ScriptBuilder.exitEarly()
|
||||
.transplant()
|
||||
.request(StackRequest.THIS, StackRequest.PARAM1)
|
||||
.target(new MethodTarget("org.netbeans.ProxyClassLoader", "getResources"))
|
||||
.decisionMethod(new Hook("lombok.netbeans.agent.PatchFixes", "getResources_decision", "boolean", "java.lang.ClassLoader", "java.lang.String"))
|
||||
.valueMethod(new Hook("lombok.netbeans.agent.PatchFixes", "getResources_value", "java.util.Enumeration", "java.lang.ClassLoader", "java.lang.String"))
|
||||
.build());
|
||||
sm.addScript(ScriptBuilder.exitEarly()
|
||||
.transplant()
|
||||
.target(new MethodTarget("org.netbeans.ProxyClassLoader", "loadClass"))
|
||||
.request(StackRequest.THIS, StackRequest.PARAM1)
|
||||
.decisionMethod(new Hook("lombok.netbeans.agent.PatchFixes", "loadClass_decision", "boolean", "java.lang.ClassLoader", "java.lang.String"))
|
||||
.valueMethod(new Hook("lombok.netbeans.agent.PatchFixes", "loadClass_value", "java.lang.Class", "java.lang.ClassLoader", "java.lang.String"))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static void patchNetbeansJavac(ScriptManager sm) {
|
||||
sm.addScript(ScriptBuilder.wrapReturnValue()
|
||||
.request(StackRequest.THIS, StackRequest.PARAM1)
|
||||
.transplant()
|
||||
.target(new MethodTarget("com.sun.tools.javac.api.JavacTaskImpl", "setTaskListener"))
|
||||
.wrapMethod(new Hook("lombok.netbeans.agent.PatchFixes", "fixContentOnSetTaskListener", "void",
|
||||
"com.sun.tools.javac.api.JavacTaskImpl", "com.sun.source.util.TaskListener"))
|
||||
.build());
|
||||
|
||||
sm.addScript(ScriptBuilder.wrapReturnValue()
|
||||
.request(StackRequest.RETURN_VALUE, StackRequest.PARAM1)
|
||||
.transplant()
|
||||
.target(new MethodTarget("org.netbeans.modules.java.source.parsing.JavacParser", "createJavacTask",
|
||||
"com.sun.tools.javac.api.JavacTaskImpl",
|
||||
"org.netbeans.api.java.source.ClasspathInfo", "javax.tools.DiagnosticListener", "java.lang.String", "boolean",
|
||||
"com.sun.tools.javac.api.ClassNamesForFileOraculum", "com.sun.tools.javac.util.CancelService"))
|
||||
.wrapMethod(new Hook("lombok.netbeans.agent.PatchFixes", "addTaskListenerWhenCallingJavac", "void",
|
||||
"com.sun.tools.javac.api.JavacTaskImpl", "org.netbeans.api.java.source.ClasspathInfo"))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static void patchNetbeansMissingPositionAwareness(ScriptManager sm) {
|
||||
sm.addScript(ScriptBuilder.replaceMethodCall()
|
||||
.target(new MethodTarget("org.netbeans.modules.java.editor.overridden.ComputeAnnotations",
|
||||
"createAnnotations"))
|
||||
.methodToReplace(new Hook("com.sun.source.util.Trees", "getTree", "com.sun.source.tree.Tree",
|
||||
"javax.lang.model.element.Element"))
|
||||
.replacementMethod(new Hook("lombok.netbeans.agent.PatchFixes", "returnNullForGeneratedNode", "com.sun.source.tree.Tree",
|
||||
"com.sun.source.util.Trees", "javax.lang.model.element.Element", "java.lang.Object"))
|
||||
.requestExtra(StackRequest.PARAM1).transplant()
|
||||
.build());
|
||||
|
||||
sm.addScript(ScriptBuilder.replaceMethodCall()
|
||||
.target(new MethodTarget("org.netbeans.modules.java.source.parsing.FindMethodRegionsVisitor",
|
||||
"visitMethod"))
|
||||
.methodToReplace(new Hook("com.sun.source.util.SourcePositions", "getEndPosition", "long",
|
||||
"com.sun.source.tree.CompilationUnitTree", "com.sun.source.tree.Tree"))
|
||||
.replacementMethod(new Hook("lombok.netbeans.agent.PatchFixes", "returnMinus1ForGeneratedNode", "long",
|
||||
"com.sun.source.util.SourcePositions", "com.sun.source.tree.CompilationUnitTree", "com.sun.source.tree.Tree"))
|
||||
.transplant().build());
|
||||
|
||||
sm.addScript(ScriptBuilder.wrapMethodCall()
|
||||
.target(new MethodTarget("org.netbeans.modules.java.source.save.CasualDiff", "filterHidden"))
|
||||
.methodToWrap(new Hook("java.lang.Iterable", "iterator", "java.util.Iterator"))
|
||||
.wrapMethod(new Hook("lombok.netbeans.agent.PatchFixes", "filterGenerated", "java.util.Iterator",
|
||||
"java.util.Iterator"))
|
||||
.transplant().build());
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
|
||||
*
|
||||
* 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.netbeans.agent;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
|
||||
import lombok.Lombok;
|
||||
import lombok.patcher.inject.LiveInjector;
|
||||
|
||||
import org.netbeans.Module;
|
||||
import org.netbeans.ProxyClassLoader;
|
||||
import org.netbeans.api.java.source.ClasspathInfo;
|
||||
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.SourcePositions;
|
||||
import com.sun.source.util.TaskListener;
|
||||
import com.sun.source.util.Trees;
|
||||
import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
|
||||
// A lot of the footwork on the netbeans support has been done by Jan Lahoda, who is awesome. (jlahoda@netbeans.org)
|
||||
// This footwork was converted into a patch script form by me (rzwitserloot). See:
|
||||
// http://code.google.com/p/projectlombok/issues/detail?id=20#c3
|
||||
public class PatchFixes {
|
||||
public static boolean loadClass_decision(ClassLoader loader, String name) throws Exception {
|
||||
return name.startsWith("lombok.");
|
||||
}
|
||||
|
||||
public static Class<?> loadClass_value(ClassLoader loader, String name) throws Exception {
|
||||
int last = name.lastIndexOf('.');
|
||||
String pkg = (last >= 0) ? name.substring(0, last) : "";
|
||||
Method m = ProxyClassLoader.class.getDeclaredMethod("selfLoadClass", String.class, String.class);
|
||||
m.setAccessible(true);
|
||||
return (Class<?>)m.invoke(loader, pkg, name);
|
||||
}
|
||||
|
||||
public static boolean getResource_decision(ClassLoader loader, String name) throws Exception {
|
||||
return name.startsWith("META-INF/services/lombok.");
|
||||
}
|
||||
|
||||
public static URL getResource_value(ClassLoader loader, String name) throws Exception {
|
||||
Method m = ProxyClassLoader.class.getDeclaredMethod("findResource", String.class);
|
||||
m.setAccessible(true);
|
||||
return (URL) m.invoke(loader, name);
|
||||
}
|
||||
|
||||
public static boolean getResources_decision(ClassLoader loader, String name) throws Exception {
|
||||
return name.startsWith("META-INF/services/lombok.");
|
||||
}
|
||||
|
||||
public static Enumeration<?> getResources_value(ClassLoader loader, String name) throws Exception {
|
||||
Method m = ProxyClassLoader.class.getDeclaredMethod("findResources", String.class);
|
||||
m.setAccessible(true);
|
||||
return (Enumeration<?>) m.invoke(loader, name);
|
||||
}
|
||||
|
||||
public static void addSelfToClassLoader(Module module, List<File> classPath) {
|
||||
if (module.getJarFile().getName().equals("org-netbeans-libs-javacimpl.jar")) {
|
||||
String lombokJarLoc = LiveInjector.findPathJar(Lombok.class);
|
||||
classPath.add(new File(lombokJarLoc));
|
||||
}
|
||||
}
|
||||
|
||||
public static void fixContentOnSetTaskListener(JavacTaskImpl that, TaskListener taskListener) throws Throwable {
|
||||
Context context = that.getContext();
|
||||
|
||||
if (context.get(TaskListener.class) != null)
|
||||
context.put(TaskListener.class, (TaskListener)null);
|
||||
if (taskListener != null) {
|
||||
try {
|
||||
Method m = JavacTaskImpl.class.getDeclaredMethod("wrap", TaskListener.class);
|
||||
try {
|
||||
m.setAccessible(true);
|
||||
} catch (SecurityException ignore) {}
|
||||
TaskListener w = (TaskListener)m.invoke(that, taskListener);
|
||||
context.put(TaskListener.class, w);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Tree returnNullForGeneratedNode(Trees trees, Element element, Object o) throws Throwable {
|
||||
try {
|
||||
Tree tree = trees.getTree(element);
|
||||
if (tree == null) return null;
|
||||
CompilationUnitTree unit = (CompilationUnitTree) o.getClass().getMethod("getCompilationUnit").invoke(o);
|
||||
int startPos = (int) trees.getSourcePositions().getStartPosition(unit, tree);
|
||||
if (startPos == -1) return null;
|
||||
return tree;
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
public static long returnMinus1ForGeneratedNode(SourcePositions that, CompilationUnitTree cu, Tree tree) {
|
||||
int start = (int) that.getStartPosition(cu, tree);
|
||||
if (start < 0) return -1;
|
||||
return that.getEndPosition(cu, tree);
|
||||
}
|
||||
|
||||
public static void addTaskListenerWhenCallingJavac(JavacTaskImpl task,
|
||||
ClasspathInfo cpInfo) throws Exception {
|
||||
if (task == null) return;
|
||||
Class<?> entryPoint = JavacTaskImpl.class.getClassLoader().loadClass("lombok.netbeans.agent.NetbeansEntryPoint");
|
||||
if (entryPoint == null) {
|
||||
/* TODO tell the user that lombok is not working. loadClass is not supposed to return null, but netbeans' loader does anyway. */
|
||||
System.err.println("[LOMBOK] ClassLoader not patched correctly.");
|
||||
} else {
|
||||
task.setTaskListener((TaskListener) entryPoint.getConstructor(Context.class).newInstance(task.getContext()));
|
||||
}
|
||||
}
|
||||
|
||||
public static Iterator<JCTree> filterGenerated(final Iterator<JCTree> it) {
|
||||
return new Iterator<JCTree>() {
|
||||
private JCTree next;
|
||||
private boolean hasNext;
|
||||
|
||||
{
|
||||
calc();
|
||||
}
|
||||
|
||||
private void calc() {
|
||||
while (it.hasNext()) {
|
||||
JCTree n = it.next();
|
||||
if (n.pos != -1) {
|
||||
hasNext = true;
|
||||
next = n;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hasNext = false;
|
||||
next = null;
|
||||
}
|
||||
|
||||
@Override public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override public JCTree next() {
|
||||
if (!hasNext) throw new NoSuchElementException();
|
||||
JCTree n = next;
|
||||
calc();
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -35,17 +36,26 @@ import java.util.List;
|
||||
public abstract class AbstractRunTests {
|
||||
protected static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
|
||||
public void compareFile(DirectoryRunner.TestParams params, File file) throws Throwable {
|
||||
public boolean compareFile(DirectoryRunner.TestParams params, File file) throws Throwable {
|
||||
StringBuilder messages = new StringBuilder();
|
||||
StringWriter writer = new StringWriter();
|
||||
transformCode(messages, writer, file);
|
||||
String expectedFile = readFile(params.getAfterDirectory(), file, false);
|
||||
String expectedMessages = readFile(params.getMessagesDirectory(), file, true);
|
||||
|
||||
StringReader r = new StringReader(expectedFile);
|
||||
BufferedReader br = new BufferedReader(r);
|
||||
if ("//ignore".equals(br.readLine())) return false;
|
||||
|
||||
compare(
|
||||
file.getName(),
|
||||
readFile(params.getAfterDirectory(), file, false),
|
||||
expectedFile,
|
||||
writer.toString(),
|
||||
readFile(params.getMessagesDirectory(), file, true),
|
||||
expectedMessages,
|
||||
messages.toString(),
|
||||
params.printErrors());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void transformCode(StringBuilder message, StringWriter result, File file) throws Throwable;
|
||||
|
||||
@@ -118,15 +118,13 @@ public class DirectoryRunner extends Runner {
|
||||
}
|
||||
switch (params.getCompiler()) {
|
||||
case DELOMBOK:
|
||||
new RunTestsViaDelombok().compareFile(params, file);
|
||||
break;
|
||||
return new RunTestsViaDelombok().compareFile(params, file);
|
||||
case ECJ:
|
||||
new RunTestsViaEcj().compareFile(params, file);
|
||||
break;
|
||||
return new RunTestsViaEcj().compareFile(params, file);
|
||||
default:
|
||||
case JAVAC:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean mustIgnore(File file) throws FileNotFoundException, IOException {
|
||||
|
||||
@@ -6,7 +6,7 @@ class Annotation {
|
||||
}
|
||||
public void method(@SuppressWarnings("unused") int x) {
|
||||
}
|
||||
public void method2(@SuppressWarnings(value = {"unused"}) int y) {
|
||||
public void method2(@SuppressWarnings({"unused"}) int y) {
|
||||
}
|
||||
public void method3(@SuppressWarnings({"unused", "unchecked"}) int z) {
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
//ignore
|
||||
@SuppressWarnings("all")
|
||||
class Annotation {
|
||||
@Override
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
public class ValErrors {
|
||||
public void nullType() {
|
||||
final val a = null;
|
||||
}
|
||||
public void unresolvableExpression() {
|
||||
final val c = d;
|
||||
final java.lang.Object c = d;
|
||||
}
|
||||
public void arrayInitializer() {
|
||||
val e = {"foo", "bar"};
|
||||
}
|
||||
}
|
||||
@@ -44,4 +44,14 @@ public class ValWeirdTypes<Z> {
|
||||
final java.util.AbstractList<java.lang.String> d = c ? a : b;
|
||||
java.util.RandomAccess confirm = c ? a : b;
|
||||
}
|
||||
public void nullType() {
|
||||
final java.lang.Object nully = null;
|
||||
}
|
||||
public void testArrays() {
|
||||
final int[] intArray = new int[]{1, 2, 3};
|
||||
final java.lang.Object[][] multiDimArray = new Object[][]{{}};
|
||||
final int[] copy = intArray;
|
||||
final java.lang.Object[] single = multiDimArray[0];
|
||||
final int singleInt = copy[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
//ignore
|
||||
@@ -0,0 +1 @@
|
||||
//ignore
|
||||
@@ -0,0 +1 @@
|
||||
//ignore
|
||||
@@ -0,0 +1 @@
|
||||
//ignore
|
||||
@@ -0,0 +1 @@
|
||||
//ignore
|
||||
@@ -0,0 +1 @@
|
||||
//ignore
|
||||
@@ -1,9 +1,9 @@
|
||||
public class ValErrors {
|
||||
public void nullType() {
|
||||
val a = null;
|
||||
}
|
||||
|
||||
public void unresolvableExpression() {
|
||||
val c = d;
|
||||
}
|
||||
|
||||
public void arrayInitializer() {
|
||||
val e = { "foo", "bar"};
|
||||
}
|
||||
}
|
||||
@@ -51,4 +51,16 @@ public class ValWeirdTypes<Z> {
|
||||
val d = c ? a : b;
|
||||
java.util.RandomAccess confirm = c ? a : b;
|
||||
}
|
||||
|
||||
public void nullType() {
|
||||
val nully = null;
|
||||
}
|
||||
|
||||
public void testArrays() {
|
||||
val intArray = new int[] {1, 2, 3};
|
||||
val multiDimArray = new Object[][] {{}};
|
||||
val copy = intArray;
|
||||
val single = multiDimArray[0];
|
||||
val singleInt = copy[0];
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
3:21 ERROR Cannot use 'val' here because initializer expression does not have a representable type: <nulltype>
|
||||
7:21 ERROR Cannot use 'val' here because initializer expression does not have a representable type: Type cannot be resolved
|
||||
3:21 ERROR Cannot use 'val' here because initializer expression does not have a representable type: Type cannot be resolved
|
||||
7:21 ERROR 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })
|
||||
@@ -0,0 +1 @@
|
||||
6:21 ERROR 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })
|
||||
@@ -39,6 +39,11 @@ public class TestLombokFilesIdempotent implements DirectoryRunner.TestParams {
|
||||
return new File("test/transform/resource/after-delombok");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getMessagesDirectory() {
|
||||
return new File("test/transform/resource/messages-idempotent");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryRunner.Compiler getCompiler() {
|
||||
return DirectoryRunner.Compiler.DELOMBOK;
|
||||
@@ -48,9 +53,4 @@ public class TestLombokFilesIdempotent implements DirectoryRunner.TestParams {
|
||||
public boolean printErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getMessagesDirectory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user