aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/javac
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lombok/javac')
-rw-r--r--src/core/lombok/javac/CapturingDiagnosticListener.java132
-rw-r--r--src/core/lombok/javac/JavacAST.java59
-rw-r--r--src/core/lombok/javac/JavacNode.java14
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java23
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java32
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java29
-rw-r--r--src/core/lombok/javac/handlers/HandleWither.java38
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java70
8 files changed, 322 insertions, 75 deletions
diff --git a/src/core/lombok/javac/CapturingDiagnosticListener.java b/src/core/lombok/javac/CapturingDiagnosticListener.java
new file mode 100644
index 00000000..45b4047a
--- /dev/null
+++ b/src/core/lombok/javac/CapturingDiagnosticListener.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012-2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.javac;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+
+/**
+ * This class stores any reported errors as {@code CompilerMessage} objects and supports removing some of these.
+ * Currently this class is only used for testing purposes.
+ */
+public class CapturingDiagnosticListener implements DiagnosticListener<JavaFileObject> {
+ private final File file;
+ private final Collection<CompilerMessage> messages;
+
+ public CapturingDiagnosticListener(File file, Collection<CompilerMessage> messages) {
+ this.file = file;
+ this.messages = messages;
+ }
+
+ @Override public void report(Diagnostic<? extends JavaFileObject> d) {
+ String msg = d.getMessage(Locale.ENGLISH);
+ Matcher m = Pattern.compile(
+ "^" + Pattern.quote(file.getAbsolutePath()) +
+ "\\s*:\\s*\\d+\\s*:\\s*(?:warning:\\s*)?(.*)$", Pattern.DOTALL).matcher(msg);
+ if (m.matches()) msg = m.group(1);
+ messages.add(new CompilerMessage(d.getLineNumber(), d.getColumnNumber(), d.getStartPosition(), d.getKind() == Kind.ERROR, msg));
+ }
+
+ public void suppress(int start, int end) {
+ Iterator<CompilerMessage> it = messages.iterator();
+ while (it.hasNext()) {
+ long pos = it.next().getPosition();
+ if (pos >= start && pos < end) it.remove();
+ }
+ }
+
+ public static final class CompilerMessage {
+ /** Line Number (starting at 1) */
+ private final long line;
+
+ /** Preferably column, but if that is hard to calculate (e.g. in ecj), then position is acceptable. */
+ private final long columnOrPosition;
+ private final long position;
+ private final boolean isError;
+ private final String message;
+
+ public CompilerMessage(long line, long columnOrPosition, long position, boolean isError, String message) {
+ this.line = line;
+ this.columnOrPosition = columnOrPosition;
+ this.position = position;
+ this.isError = isError;
+ this.message = message;
+ }
+
+ public long getLine() {
+ return line;
+ }
+
+ public long getPosition() {
+ return position;
+ }
+
+ public long getColumnOrPosition() {
+ return columnOrPosition;
+ }
+
+ public boolean isError() {
+ return isError;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @Override public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (isError ? 1231 : 1237);
+ result = prime * result + (int) (line ^ (line >>> 32));
+ result = prime * result + ((message == null) ? 0 : message.hashCode());
+ result = prime * result + (int) (columnOrPosition ^ (columnOrPosition >>> 32));
+ return result;
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ CompilerMessage other = (CompilerMessage) obj;
+ if (isError != other.isError) return false;
+ if (line != other.line) return false;
+ if (message == null) {
+ if (other.message != null) return false;
+ } else if (!message.equals(other.message)) return false;
+ if (columnOrPosition != other.columnOrPosition) return false;
+ return true;
+ }
+
+ @Override public String toString() {
+ return String.format("%d:%d %s %s", line, columnOrPosition, isError ? "ERROR" : "WARNING", message);
+ }
+ }
+}
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index c2c55f1d..71c17538 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -28,6 +28,7 @@ import java.util.List;
import javax.annotation.processing.Messager;
import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
import lombok.core.AST;
@@ -50,6 +51,8 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -287,8 +290,28 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
if (node != null) nodes.add(node);
}
+ private static final Field JAVAC7_DEFERRED_DIAGNOSTICS;
+
+ static {
+ Field f = null;
+ try {
+ f = Log.class.getField("deferredDiagnostics");
+ if (!ListBuffer.class.isAssignableFrom(f.getType())) throw new NoSuchFieldException("deferredDiagnostics does not have the expected type.");
+ } catch (NoSuchFieldException e) {}
+ JAVAC7_DEFERRED_DIAGNOSTICS = f;
+ }
+
+ /**
+ * Attempts to remove any compiler errors generated by java whose reporting position is located anywhere between the start and end of the supplied node.
+ */
+ void removeDeferredErrors(JavacNode node) {
+ DiagnosticPosition pos = node.get().pos();
+ JCCompilationUnit top = (JCCompilationUnit) top().get();
+ removeFromDeferredDiagnostics(pos.getStartPosition(), pos.getEndPosition(top.endPositions));
+ }
+
/** Supply either a position or a node (in that case, position of the node is used) */
- void printMessage(Diagnostic.Kind kind, String message, JavacNode node, DiagnosticPosition pos) {
+ void printMessage(Diagnostic.Kind kind, String message, JavacNode node, DiagnosticPosition pos, boolean attemptToRemoveErrorsInRange) {
JavaFileObject oldSource = null;
JavaFileObject newSource = null;
JCTree astObject = node == null ? null : node.get();
@@ -298,6 +321,9 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
oldSource = log.useSource(newSource);
if (pos == null) pos = astObject.pos();
}
+ if (pos != null && attemptToRemoveErrorsInRange) {
+ removeFromDeferredDiagnostics(pos.getStartPosition(), pos.getEndPosition(top.endPositions));
+ }
try {
switch (kind) {
case ERROR:
@@ -319,6 +345,35 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
if (oldSource != null) log.useSource(oldSource);
}
}
+
+ private void removeFromDeferredDiagnostics(int startPos, int endPos) {
+ DiagnosticListener<?> listener = getContext().get(DiagnosticListener.class);
+ if (listener instanceof CapturingDiagnosticListener) {
+ ((CapturingDiagnosticListener) listener).suppress(startPos, endPos);
+ }
+ try {
+ if (JAVAC7_DEFERRED_DIAGNOSTICS != null) {
+ ListBuffer<?> deferredDiagnostics = (ListBuffer<?>) JAVAC7_DEFERRED_DIAGNOSTICS.get(log);
+ ListBuffer<Object> newDeferredDiagnostics = ListBuffer.lb();
+ for (Object diag : deferredDiagnostics) {
+ if (!(diag instanceof JCDiagnostic)) {
+ newDeferredDiagnostics.add(diag);
+ continue;
+ }
+ long here = ((JCDiagnostic) diag).getStartPosition();
+ if (here >= startPos && here < endPos) {
+ // We eliminate it
+ } else {
+ newDeferredDiagnostics.add(diag);
+ }
+ }
+ JAVAC7_DEFERRED_DIAGNOSTICS.set(log, newDeferredDiagnostics);
+ }
+ } catch (Exception e) {
+ // We do not expect failure here; if failure does occur, the best course of action is to silently continue; the result will be that the error output of
+ // javac will contain rather a lot of messages, but this is a lot better than just crashing during compilation!
+ }
+ }
/** {@inheritDoc} */
@Override protected void setElementInASTCollection(Field field, Object refField, List<Collection<?>> chain, Collection<?> collection, int idx, JCTree newN) throws IllegalAccessException {
diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java
index b478781b..16c06430 100644
--- a/src/core/lombok/javac/JavacNode.java
+++ b/src/core/lombok/javac/JavacNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -209,31 +209,35 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre
return ast.toName(name);
}
+ public void removeDeferredErrors() {
+ ast.removeDeferredErrors(this);
+ }
+
/**
* Generates an compiler error focused on the AST node represented by this node object.
*/
@Override public void addError(String message) {
- ast.printMessage(Diagnostic.Kind.ERROR, message, this, null);
+ ast.printMessage(Diagnostic.Kind.ERROR, message, this, null, true);
}
/**
* Generates an compiler error focused on the AST node represented by this node object.
*/
public void addError(String message, DiagnosticPosition pos) {
- ast.printMessage(Diagnostic.Kind.ERROR, message, null, pos);
+ ast.printMessage(Diagnostic.Kind.ERROR, message, null, pos, true);
}
/**
* Generates a compiler warning focused on the AST node represented by this node object.
*/
@Override public void addWarning(String message) {
- ast.printMessage(Diagnostic.Kind.WARNING, message, this, null);
+ ast.printMessage(Diagnostic.Kind.WARNING, message, this, null, false);
}
/**
* Generates a compiler warning focused on the AST node represented by this node object.
*/
public void addWarning(String message, DiagnosticPosition pos) {
- ast.printMessage(Diagnostic.Kind.WARNING, message, null, pos);
+ ast.printMessage(Diagnostic.Kind.WARNING, message, null, pos, false);
}
}
diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java
index b6c31f83..bb883ca4 100644
--- a/src/core/lombok/javac/handlers/HandleConstructor.java
+++ b/src/core/lombok/javac/handlers/HandleConstructor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2011 The Project Lombok Authors.
+ * Copyright (C) 2010-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -60,12 +60,13 @@ public class HandleConstructor {
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, NoArgsConstructor.class.getSimpleName())) return;
+ List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor=", annotationNode);
NoArgsConstructor ann = annotation.getInstance();
AccessLevel level = ann.access();
String staticName = ann.staticName();
if (level == AccessLevel.NONE) return;
List<JavacNode> fields = List.nil();
- new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, false, annotationNode);
+ new HandleConstructor().generateConstructor(typeNode, level, onConstructor, fields, staticName, false, false, annotationNode);
}
}
@@ -76,13 +77,14 @@ public class HandleConstructor {
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, RequiredArgsConstructor.class.getSimpleName())) return;
+ List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor=", annotationNode);
RequiredArgsConstructor ann = annotation.getInstance();
AccessLevel level = ann.access();
String staticName = ann.staticName();
@SuppressWarnings("deprecation")
boolean suppressConstructorProperties = ann.suppressConstructorProperties();
if (level == AccessLevel.NONE) return;
- new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, false, suppressConstructorProperties, annotationNode);
+ new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findRequiredFields(typeNode), staticName, false, suppressConstructorProperties, annotationNode);
}
}
@@ -110,13 +112,14 @@ public class HandleConstructor {
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, AllArgsConstructor.class.getSimpleName())) return;
+ List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor=", annotationNode);
AllArgsConstructor ann = annotation.getInstance();
AccessLevel level = ann.access();
String staticName = ann.staticName();
@SuppressWarnings("deprecation")
boolean suppressConstructorProperties = ann.suppressConstructorProperties();
if (level == AccessLevel.NONE) return;
- new HandleConstructor().generateConstructor(typeNode, level, findAllFields(typeNode), staticName, false, suppressConstructorProperties, annotationNode);
+ new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findAllFields(typeNode), staticName, false, suppressConstructorProperties, annotationNode);
}
}
@@ -152,14 +155,14 @@ public class HandleConstructor {
}
public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists, JavacNode source) {
- generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, false, source);
+ generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), staticName, skipIfConstructorExists, false, source);
}
public void generateAllArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists, JavacNode source) {
- generateConstructor(typeNode, level, findAllFields(typeNode), staticName, skipIfConstructorExists, false, source);
+ generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findAllFields(typeNode), staticName, skipIfConstructorExists, false, source);
}
- public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JavacNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, JavacNode source) {
+ public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, JavacNode source) {
boolean staticConstrRequired = staticName != null && !staticName.equals("");
if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return;
@@ -183,7 +186,7 @@ public class HandleConstructor {
}
}
- JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source.get());
+ JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, suppressConstructorProperties, source.get());
injectMethod(typeNode, constr);
if (staticConstrRequired) {
JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, fields, source.get());
@@ -204,7 +207,7 @@ public class HandleConstructor {
mods.annotations = mods.annotations.append(annotation);
}
- private JCMethodDecl createConstructor(AccessLevel level, JavacNode typeNode, List<JavacNode> fields, boolean suppressConstructorProperties, JCTree source) {
+ private JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, boolean suppressConstructorProperties, JCTree source) {
TreeMaker maker = typeNode.getTreeMaker();
boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0;
@@ -234,6 +237,8 @@ public class HandleConstructor {
if (!suppressConstructorProperties && level != AccessLevel.PRIVATE && !isLocalType(typeNode)) {
addConstructorProperties(mods, typeNode, fields);
}
+ if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor));
+
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"),
null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source);
}
diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java
index 65947c72..bc68d5ad 100644
--- a/src/core/lombok/javac/handlers/HandleGetter.java
+++ b/src/core/lombok/javac/handlers/HandleGetter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,8 @@
*/
package lombok.javac.handlers;
-import static lombok.javac.handlers.JavacHandlerUtil.*;
import static lombok.javac.Javac.*;
+import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.util.Collection;
import java.util.Collections;
@@ -32,9 +32,9 @@ import java.util.Map;
import lombok.AccessLevel;
import lombok.Delegate;
import lombok.Getter;
+import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.TransformationsUtil;
-import lombok.core.AST.Kind;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
@@ -43,7 +43,6 @@ import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
@@ -60,10 +59,11 @@ import com.sun.tools.javac.tree.JCTree.JCSynchronized;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
/**
* Handles the {@code lombok.Getter} annotation for javac.
@@ -123,8 +123,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
//The annotation will make it happen, so we can skip it.
return;
}
-
- createGetterForField(level, fieldNode, fieldNode, false, lazy);
+ createGetterForField(level, fieldNode, fieldNode, false, lazy, List.<JCAnnotation>nil());
}
@Override public void handle(AnnotationValues<Getter> annotation, JCAnnotation ast, JavacNode annotationNode) {
@@ -144,25 +143,30 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
if (node == null) return;
+ List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Getter(onMethod=", annotationNode);
+
switch (node.getKind()) {
case FIELD:
- createGetterForFields(level, fields, annotationNode, true, lazy);
+ createGetterForFields(level, fields, annotationNode, true, lazy, onMethod);
break;
case TYPE:
+ if (!onMethod.isEmpty()) {
+ annotationNode.addError("'onMethod' is not supported for @Getter on a type.");
+ }
if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type.");
generateGetterForType(node, annotationNode, level, false);
break;
}
}
- private void createGetterForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, boolean lazy) {
+ private void createGetterForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, boolean lazy, List<JCAnnotation> onMethod) {
for (JavacNode fieldNode : fieldNodes) {
- createGetterForField(level, fieldNode, errorNode, whineIfExists, lazy);
+ createGetterForField(level, fieldNode, errorNode, whineIfExists, lazy, onMethod);
}
}
private void createGetterForField(AccessLevel level,
- JavacNode fieldNode, JavacNode source, boolean whineIfExists, boolean lazy) {
+ JavacNode fieldNode, JavacNode source, boolean whineIfExists, boolean lazy, List<JCAnnotation> onMethod) {
if (fieldNode.getKind() != Kind.FIELD) {
source.addError("@Getter is only supported on a class or a field.");
return;
@@ -208,10 +212,10 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
- injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), lazy, source.get()));
+ injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source.get(), lazy, onMethod));
}
- private JCMethodDecl createGetter(long access, JavacNode field, TreeMaker treeMaker, boolean lazy, JCTree source) {
+ private JCMethodDecl createGetter(long access, JavacNode field, TreeMaker treeMaker, JCTree source, boolean lazy, List<JCAnnotation> onMethod) {
JCVariableDecl fieldNode = (JCVariableDecl) field.get();
// Remember the type; lazy will change it
@@ -240,7 +244,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field);
- List<JCAnnotation> annsOnMethod = nonNulls.appendList(nullables);
+ List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod).appendList(nonNulls).appendList(nullables);
if (isFieldDeprecated(field)) {
annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(chainDots(field, "java", "lang", "Deprecated"), List.<JCExpression>nil()));
}
diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java
index e2c75e2e..c1e03c35 100644
--- a/src/core/lombok/javac/handlers/HandleSetter.java
+++ b/src/core/lombok/javac/handlers/HandleSetter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -118,7 +118,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
return;
}
- createSetterForField(level, fieldNode, fieldNode, false);
+ createSetterForField(level, fieldNode, fieldNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil());
}
@Override public void handle(AnnotationValues<Setter> annotation, JCAnnotation ast, JavacNode annotationNode) {
@@ -130,26 +130,28 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
if (level == AccessLevel.NONE || node == null) return;
+ List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Setter(onMethod=", annotationNode);
+ List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Setter(onParam=", annotationNode);
+
switch (node.getKind()) {
case FIELD:
- createSetterForFields(level, fields, annotationNode, true);
+ createSetterForFields(level, fields, annotationNode, true, onMethod, onParam);
break;
case TYPE:
+ if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @Setter on a type.");
+ if (!onParam.isEmpty()) annotationNode.addError("'onParam' is not supported for @Setter on a type.");
generateSetterForType(node, annotationNode, level, false);
break;
}
}
- private void createSetterForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists) {
-
+ private void createSetterForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
for (JavacNode fieldNode : fieldNodes) {
- createSetterForField(level, fieldNode, errorNode, whineIfExists);
+ createSetterForField(level, fieldNode, errorNode, whineIfExists, onMethod, onParam);
}
}
- private void createSetterForField(AccessLevel level,
- JavacNode fieldNode, JavacNode source, boolean whineIfExists) {
-
+ private void createSetterForField(AccessLevel level, JavacNode fieldNode, JavacNode source, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
if (fieldNode.getKind() != Kind.FIELD) {
fieldNode.addError("@Setter is only supported on a class or a field.");
return;
@@ -188,11 +190,11 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
- JCMethodDecl createdSetter = createSetter(access, fieldNode, fieldNode.getTreeMaker(), source.get());
+ JCMethodDecl createdSetter = createSetter(access, fieldNode, fieldNode.getTreeMaker(), source.get(), onMethod, onParam);
injectMethod(fieldNode.up(), createdSetter);
}
- private JCMethodDecl createSetter(long access, JavacNode field, TreeMaker treeMaker, JCTree source) {
+ private JCMethodDecl createSetter(long access, JavacNode field, TreeMaker treeMaker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
String setterName = toSetterName(field);
boolean returnThis = shouldReturnThis(field);
if (setterName == null) return null;
@@ -207,7 +209,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
Name methodName = field.toName(setterName);
- List<JCAnnotation> annsOnParam = nonNulls.appendList(nullables);
+ List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(nonNulls).appendList(nullables);
JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.FINAL, annsOnParam), fieldDecl.name, fieldDecl.vartype, null);
@@ -241,10 +243,11 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;
- List<JCAnnotation> annsOnMethod = List.nil();
+ List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod);
if (isFieldDeprecated(field)) {
annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(chainDots(field, "java", "lang", "Deprecated"), List.<JCExpression>nil()));
}
+
return recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType,
methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source);
}
diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java
index 64011f91..ba5aa72d 100644
--- a/src/core/lombok/javac/handlers/HandleWither.java
+++ b/src/core/lombok/javac/handlers/HandleWither.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -109,16 +109,12 @@ public class HandleWither extends JavacAnnotationHandler<Wither> {
* @param pos The node responsible for generating the wither (the {@code @Value} or {@code @Wither} annotation).
*/
public void generateWitherForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level) {
- for (JavacNode child : fieldNode.down()) {
- if (child.getKind() == Kind.ANNOTATION) {
- if (annotationTypeMatches(Wither.class, child)) {
- //The annotation will make it happen, so we can skip it.
- return;
- }
- }
+ if (hasAnnotation(Wither.class, fieldNode)) {
+ //The annotation will make it happen, so we can skip it.
+ return;
}
- createWitherForField(level, fieldNode, fieldNode, false);
+ createWitherForField(level, fieldNode, fieldNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil());
}
@Override public void handle(AnnotationValues<Wither> annotation, JCAnnotation ast, JavacNode annotationNode) {
@@ -130,25 +126,28 @@ public class HandleWither extends JavacAnnotationHandler<Wither> {
if (level == AccessLevel.NONE || node == null) return;
+ List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Setter(onMethod=", annotationNode);
+ List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Setter(onParam=", annotationNode);
+
switch (node.getKind()) {
case FIELD:
- createWitherForFields(level, fields, annotationNode, true);
+ createWitherForFields(level, fields, annotationNode, true, onMethod, onParam);
break;
case TYPE:
+ if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @Wither on a type.");
+ if (!onParam.isEmpty()) annotationNode.addError("'onParam' is not supported for @Wither on a type.");
generateWitherForType(node, annotationNode, level, false);
break;
}
}
- private void createWitherForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists) {
+ private void createWitherForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
for (JavacNode fieldNode : fieldNodes) {
- createWitherForField(level, fieldNode, errorNode, whineIfExists);
+ createWitherForField(level, fieldNode, errorNode, whineIfExists, onMethod, onParam);
}
}
- private void createWitherForField(AccessLevel level,
- JavacNode fieldNode, JavacNode source, boolean whineIfExists) {
-
+ private void createWitherForField(AccessLevel level, JavacNode fieldNode, JavacNode source, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
if (fieldNode.getKind() != Kind.FIELD) {
fieldNode.addError("@Wither is only supported on a class or a field.");
return;
@@ -197,11 +196,11 @@ public class HandleWither extends JavacAnnotationHandler<Wither> {
long access = toJavacModifier(level);
- JCMethodDecl createdWither = createWither(access, fieldNode, fieldNode.getTreeMaker(), source.get());
+ JCMethodDecl createdWither = createWither(access, fieldNode, fieldNode.getTreeMaker(), source.get(), onMethod, onParam);
injectMethod(fieldNode.up(), createdWither);
}
- private JCMethodDecl createWither(long access, JavacNode field, TreeMaker treeMaker, JCTree source) {
+ private JCMethodDecl createWither(long access, JavacNode field, TreeMaker treeMaker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
String witherName = toWitherName(field);
if (witherName == null) return null;
@@ -212,7 +211,7 @@ public class HandleWither extends JavacAnnotationHandler<Wither> {
List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
Name methodName = field.toName(witherName);
- List<JCAnnotation> annsOnParam = nonNulls.appendList(nullables);
+ List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(nonNulls).appendList(nullables);
JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.FINAL, annsOnParam), fieldDecl.name, fieldDecl.vartype, null);
@@ -260,7 +259,8 @@ public class HandleWither extends JavacAnnotationHandler<Wither> {
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;
- List<JCAnnotation> annsOnMethod = List.nil();
+ List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod);
+
if (isFieldDeprecated(field)) {
annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(chainDots(field, "java", "lang", "Deprecated"), List.<JCExpression>nil()));
}
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index ad3e4a17..c2de5b05 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -63,8 +63,8 @@ import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCStatement;
-import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
+import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
@@ -920,33 +920,77 @@ public class JavacHandlerUtil {
return problematic.toList();
}
- static List<JCExpression> getAndRemoveAnnotationParameter(JCAnnotation ast, String parameterName) {
+ static List<JCAnnotation> unboxAndRemoveAnnotationParameter(JCAnnotation ast, String parameterName, String errorName, JavacNode errorNode) {
ListBuffer<JCExpression> params = ListBuffer.lb();
- List<JCExpression> result = List.nil();
+ ListBuffer<JCAnnotation> result = ListBuffer.lb();
+ errorNode.removeDeferredErrors();
+
+ outer:
for (JCExpression param : ast.args) {
+ String nameOfParam = "value";
+ JCExpression valueOfParam = null;
if (param instanceof JCAssign) {
JCAssign assign = (JCAssign) param;
if (assign.lhs instanceof JCIdent) {
JCIdent ident = (JCIdent) assign.lhs;
- if (parameterName.equals(ident.name.toString())) {
- if (assign.rhs instanceof JCNewArray) {
- result = ((JCNewArray) assign.rhs).elems;
+ nameOfParam = ident.name.toString();
+ }
+ valueOfParam = assign.rhs;
+ }
+
+ if (!parameterName.equals(nameOfParam)) {
+ params.append(param);
+ continue outer;
+ }
+
+ if (valueOfParam instanceof JCAnnotation) {
+ String dummyAnnotationName = ((JCAnnotation) valueOfParam).annotationType.toString();
+ dummyAnnotationName = dummyAnnotationName.replace("_", "");
+ if (dummyAnnotationName.length() > 0) {
+ errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
+ continue outer;
+ }
+ for (JCExpression expr : ((JCAnnotation) valueOfParam).args) {
+ if (expr instanceof JCAssign && ((JCAssign) expr).lhs instanceof JCIdent) {
+ JCIdent id = (JCIdent) ((JCAssign) expr).lhs;
+ if ("value".equals(id.name.toString())) {
+ expr = ((JCAssign) expr).rhs;
} else {
- result = result.append(assign.rhs);
+ errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
+ continue outer;
}
- continue;
+ }
+
+ if (expr instanceof JCAnnotation) {
+ result.append((JCAnnotation) expr);
+ } else if (expr instanceof JCNewArray) {
+ for (JCExpression expr2 : ((JCNewArray) expr).elems) {
+ if (expr2 instanceof JCAnnotation) {
+ result.append((JCAnnotation) expr2);
+ } else {
+ errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
+ continue outer;
+ }
+ }
+ } else {
+ errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
+ continue outer;
}
}
+ } else {
+ if (valueOfParam instanceof JCNewArray && ((JCNewArray) valueOfParam).elems.isEmpty()) {
+ // Then we just remove it and move on (it's onMethod={} for example).
+ } else {
+ errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
+ }
}
-
- params.append(param);
}
ast.args = params.toList();
- return result;
+ return result.toList();
}
- static List<JCAnnotation> copyAnnotations(List<JCExpression> in) {
+ static List<JCAnnotation> copyAnnotations(List<? extends JCExpression> in) {
ListBuffer<JCAnnotation> out = ListBuffer.lb();
for (JCExpression expr : in) {
if (!(expr instanceof JCAnnotation)) continue;