aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lombok/Data.java13
-rw-r--r--src/lombok/Getter.java4
-rw-r--r--src/lombok/Setter.java4
-rw-r--r--src/lombok/eclipse/Eclipse.java128
-rw-r--r--src/lombok/eclipse/HandlerLibrary.java90
-rw-r--r--src/lombok/eclipse/handlers/HandleData.java49
-rw-r--r--src/lombok/eclipse/handlers/HandleGetter.java50
-rw-r--r--src/lombok/eclipse/handlers/HandleSetter.java43
-rw-r--r--src/lombok/javac/HandlerLibrary.java64
-rw-r--r--src/lombok/javac/Javac.java102
-rw-r--r--src/lombok/javac/handlers/HandleData.java49
-rw-r--r--src/lombok/javac/handlers/HandleGetter.java53
-rw-r--r--src/lombok/javac/handlers/HandleSetter.java52
13 files changed, 506 insertions, 195 deletions
diff --git a/src/lombok/Data.java b/src/lombok/Data.java
new file mode 100644
index 00000000..e985a28a
--- /dev/null
+++ b/src/lombok/Data.java
@@ -0,0 +1,13 @@
+package lombok;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.SOURCE)
+public @interface Data {
+ String staticConstructor() default "";
+ int hashCodePrime() default 31;
+}
diff --git a/src/lombok/Getter.java b/src/lombok/Getter.java
index a714ead4..7510bf24 100644
--- a/src/lombok/Getter.java
+++ b/src/lombok/Getter.java
@@ -8,5 +8,7 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Getter {
- AccessLevel value() default lombok.AccessLevel.PUBLIC;
+ lombok.AccessLevel DEFAULT_ACCESS_LEVEL = lombok.AccessLevel.PUBLIC;
+
+ lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;
}
diff --git a/src/lombok/Setter.java b/src/lombok/Setter.java
index fc6a311b..acd1d180 100644
--- a/src/lombok/Setter.java
+++ b/src/lombok/Setter.java
@@ -8,5 +8,7 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Setter {
- AccessLevel value() default lombok.AccessLevel.PUBLIC;
+ lombok.AccessLevel DEFAULT_ACCESS_LEVEL = lombok.AccessLevel.PUBLIC;
+
+ lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;
}
diff --git a/src/lombok/eclipse/Eclipse.java b/src/lombok/eclipse/Eclipse.java
index 961b9536..baac26a9 100644
--- a/src/lombok/eclipse/Eclipse.java
+++ b/src/lombok/eclipse/Eclipse.java
@@ -1,12 +1,41 @@
package lombok.eclipse;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import lombok.core.AnnotationValues;
+import lombok.core.TypeLibrary;
+import lombok.core.TypeResolver;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues.AnnotationValue;
+import lombok.eclipse.EclipseAST.Node;
+
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.Literal;
+import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.osgi.framework.Bundle;
public class Eclipse {
+ private Eclipse() {
+ //Prevent instantiation
+ }
+
private static final String DEFAULT_BUNDLE = "org.eclipse.jdt.core";
public static void error(String message) {
error(message, DEFAULT_BUNDLE, null);
@@ -41,4 +70,103 @@ public class Eclipse {
}
return sb.toString();
}
+
+ public static boolean annotationTypeMatches(Class<? extends java.lang.annotation.Annotation> type, Node node) {
+ if ( node.getKind() != Kind.ANNOTATION ) return false;
+ TypeReference typeRef = ((Annotation)node.get()).type;
+ if ( typeRef == null || typeRef.getTypeName() == null ) return false;
+ String typeName = toQualifiedName(typeRef.getTypeName());
+
+ TypeLibrary library = new TypeLibrary();
+ library.addType(type.getName());
+ TypeResolver resolver = new TypeResolver(library, node.getPackageDeclaration(), node.getImportStatements());
+ Collection<String> typeMatches = resolver.findTypeMatches(node, typeName);
+
+ for ( String match : typeMatches ) {
+ if ( match.equals(type.getName()) ) return true;
+ }
+
+ return false;
+ }
+
+ public static <A extends java.lang.annotation.Annotation> AnnotationValues<A>
+ createAnnotation(Class<A> type, final Node annotationNode) {
+ Annotation annotation = (Annotation) annotationNode.get();
+ Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>();
+
+ final MemberValuePair[] pairs = annotation.memberValuePairs();
+ for ( Method m : type.getDeclaredMethods() ) {
+ if ( !Modifier.isPublic(m.getModifiers()) ) continue;
+ String name = m.getName();
+ List<String> raws = new ArrayList<String>();
+ List<Object> guesses = new ArrayList<Object>();
+ Expression fullExpression = null;
+ Expression[] expressions = null;
+
+ if ( pairs != null ) for ( MemberValuePair pair : pairs ) {
+ char[] n = pair.name;
+ String mName = n == null ? "value" : new String(name);
+ if ( !mName.equals(name) ) continue;
+ fullExpression = pair.value;
+ }
+
+ if ( fullExpression != null ) {
+ if ( fullExpression instanceof ArrayInitializer ) {
+ expressions = ((ArrayInitializer)fullExpression).expressions;
+ } else expressions = new Expression[] { fullExpression };
+ for ( Expression ex : expressions ) {
+ StringBuffer sb = new StringBuffer();
+ ex.print(0, sb);
+ raws.add(sb.toString());
+ guesses.add(calculateValue(ex));
+ }
+ }
+
+ final Expression fullExpr = fullExpression;
+ final Expression[] exprs = expressions;
+
+ values.put(name, new AnnotationValue(annotationNode, raws, guesses) {
+ @Override public void setError(String message, int valueIdx) {
+ Expression ex;
+ if ( valueIdx == -1 ) ex = fullExpr;
+ else ex = exprs[valueIdx];
+
+ int sourceStart = ex.sourceStart;
+ int sourceEnd = ex.sourceEnd;
+
+ annotationNode.addError(message, sourceStart, sourceEnd);
+ }
+ });
+ }
+
+ return new AnnotationValues<A>(type, values, annotationNode);
+ }
+
+ private static Object calculateValue(Expression e) {
+ if ( e instanceof Literal ) {
+ ((Literal)e).computeConstant();
+ switch ( e.constant.typeID() ) {
+ case TypeIds.T_int: return e.constant.intValue();
+ case TypeIds.T_byte: return e.constant.byteValue();
+ case TypeIds.T_short: return e.constant.shortValue();
+ case TypeIds.T_char: return e.constant.charValue();
+ case TypeIds.T_float: return e.constant.floatValue();
+ case TypeIds.T_double: return e.constant.doubleValue();
+ case TypeIds.T_boolean: return e.constant.booleanValue();
+ case TypeIds.T_long: return e.constant.longValue();
+ case TypeIds.T_JavaLangString: return e.constant.stringValue();
+ default: return null;
+ }
+ } else if ( e instanceof ClassLiteralAccess ) {
+ return Eclipse.toQualifiedName(((ClassLiteralAccess)e).type.getTypeName());
+ } else if ( e instanceof SingleNameReference ) {
+ return new String(((SingleNameReference)e).token);
+ } else if ( e instanceof QualifiedNameReference ) {
+ String qName = Eclipse.toQualifiedName(((QualifiedNameReference)e).tokens);
+ int idx = qName.lastIndexOf('.');
+ return idx == -1 ? qName : qName.substring(idx+1);
+ }
+
+ return null;
+ }
}
diff --git a/src/lombok/eclipse/HandlerLibrary.java b/src/lombok/eclipse/HandlerLibrary.java
index 86efd53e..39864e8e 100644
--- a/src/lombok/eclipse/HandlerLibrary.java
+++ b/src/lombok/eclipse/HandlerLibrary.java
@@ -3,13 +3,10 @@ package lombok.eclipse;
import static lombok.eclipse.Eclipse.toQualifiedName;
import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
@@ -18,20 +15,11 @@ import lombok.core.AnnotationValues;
import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
import lombok.core.TypeResolver;
-import lombok.core.AnnotationValues.AnnotationValue;
import lombok.core.AnnotationValues.AnnotationValueDecodeFail;
import lombok.eclipse.EclipseAST.Node;
-import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
-import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.Expression;
-import org.eclipse.jdt.internal.compiler.ast.Literal;
-import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
-import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
-import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
-import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
public class HandlerLibrary {
private TypeLibrary typeLibrary = new TypeLibrary();
@@ -47,54 +35,8 @@ public class HandlerLibrary {
public boolean handle(org.eclipse.jdt.internal.compiler.ast.Annotation annotation,
final Node annotationNode) {
- Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>();
-
- final MemberValuePair[] pairs = annotation.memberValuePairs();
- for ( Method m : annotationClass.getDeclaredMethods() ) {
- if ( !Modifier.isPublic(m.getModifiers()) ) continue;
- String name = m.getName();
- List<String> raws = new ArrayList<String>();
- List<Object> guesses = new ArrayList<Object>();
- Expression fullExpression = null;
- Expression[] expressions = null;
-
- if ( pairs != null ) for ( MemberValuePair pair : pairs ) {
- char[] n = pair.name;
- String mName = n == null ? "value" : new String(name);
- if ( !mName.equals(name) ) continue;
- fullExpression = pair.value;
- }
-
- if ( fullExpression != null ) {
- if ( fullExpression instanceof ArrayInitializer ) {
- expressions = ((ArrayInitializer)fullExpression).expressions;
- } else expressions = new Expression[] { fullExpression };
- for ( Expression ex : expressions ) {
- StringBuffer sb = new StringBuffer();
- ex.print(0, sb);
- raws.add(sb.toString());
- guesses.add(calculateValue(ex));
- }
- }
-
- final Expression fullExpr = fullExpression;
- final Expression[] exprs = expressions;
-
- values.put(name, new AnnotationValue(annotationNode, raws, guesses) {
- @Override public void setError(String message, int valueIdx) {
- Expression ex;
- if ( valueIdx == -1 ) ex = fullExpr;
- else ex = exprs[valueIdx];
-
- int sourceStart = ex.sourceStart;
- int sourceEnd = ex.sourceEnd;
-
- annotationNode.addError(message, sourceStart, sourceEnd);
- }
- });
- }
-
- return handler.handle(new AnnotationValues<T>(annotationClass, values, annotationNode), annotation, annotationNode);
+ AnnotationValues<T> annValues = Eclipse.createAnnotation(annotationClass, annotationNode);
+ return handler.handle(annValues, annotation, annotationNode);
}
}
@@ -103,34 +45,6 @@ public class HandlerLibrary {
private Collection<EclipseASTVisitor> visitorHandlers = new ArrayList<EclipseASTVisitor>();
- private static Object calculateValue(Expression e) {
- if ( e instanceof Literal ) {
- ((Literal)e).computeConstant();
- switch ( e.constant.typeID() ) {
- case TypeIds.T_int: return e.constant.intValue();
- case TypeIds.T_byte: return e.constant.byteValue();
- case TypeIds.T_short: return e.constant.shortValue();
- case TypeIds.T_char: return e.constant.charValue();
- case TypeIds.T_float: return e.constant.floatValue();
- case TypeIds.T_double: return e.constant.doubleValue();
- case TypeIds.T_boolean: return e.constant.booleanValue();
- case TypeIds.T_long: return e.constant.longValue();
- case TypeIds.T_JavaLangString: return e.constant.stringValue();
- default: return null;
- }
- } else if ( e instanceof ClassLiteralAccess ) {
- return Eclipse.toQualifiedName(((ClassLiteralAccess)e).type.getTypeName());
- } else if ( e instanceof SingleNameReference ) {
- return new String(((SingleNameReference)e).token);
- } else if ( e instanceof QualifiedNameReference ) {
- String qName = Eclipse.toQualifiedName(((QualifiedNameReference)e).tokens);
- int idx = qName.lastIndexOf('.');
- return idx == -1 ? qName : qName.substring(idx+1);
- }
-
- return null;
- }
-
public static HandlerLibrary load() {
HandlerLibrary lib = new HandlerLibrary();
diff --git a/src/lombok/eclipse/handlers/HandleData.java b/src/lombok/eclipse/handlers/HandleData.java
new file mode 100644
index 00000000..64540e95
--- /dev/null
+++ b/src/lombok/eclipse/handlers/HandleData.java
@@ -0,0 +1,49 @@
+package lombok.eclipse.handlers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.mangosdk.spi.ProviderFor;
+
+import lombok.Data;
+import lombok.core.AnnotationValues;
+import lombok.core.AST.Kind;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseAST.Node;
+
+@ProviderFor(EclipseAnnotationHandler.class)
+public class HandleData implements EclipseAnnotationHandler<Data> {
+ @Override public boolean handle(AnnotationValues<Data> annotation, Annotation ast, Node annotationNode) {
+ Node typeNode = annotationNode.up();
+
+ TypeDeclaration typeDecl = null;
+ if ( typeNode.get() instanceof TypeDeclaration ) typeDecl = (TypeDeclaration) typeNode.get();
+ int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
+ boolean notAClass = (modifiers &
+ (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
+
+ if ( typeDecl == null || notAClass ) {
+ annotationNode.addError("@Data is only supported on a class.");
+ return false;
+ }
+
+ List<Node> nodesForEquality = new ArrayList<Node>();
+ for ( Node child : typeNode.down() ) {
+ if ( child.getKind() != Kind.FIELD ) continue;
+ FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
+ //Skip static fields.
+ if ( (fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0 ) continue;
+ if ( (fieldDecl.modifiers & ClassFileConstants.AccTransient) == 0 ) nodesForEquality.add(child);
+ new HandleGetter().generateGetterForField(child, annotationNode.get());
+ if ( (fieldDecl.modifiers & ClassFileConstants.AccFinal) == 0 )
+ new HandleSetter().generateSetterForField(child, annotationNode.get());
+ }
+
+ //TODO generate constructor, hashCode, equals, toString.
+ return true;
+ }
+}
diff --git a/src/lombok/eclipse/handlers/HandleGetter.java b/src/lombok/eclipse/handlers/HandleGetter.java
index ca561a48..798705da 100644
--- a/src/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/lombok/eclipse/handlers/HandleGetter.java
@@ -2,9 +2,12 @@ package lombok.eclipse.handlers;
import static lombok.eclipse.handlers.PKG.*;
+import lombok.AccessLevel;
import lombok.Getter;
import lombok.core.AnnotationValues;
import lombok.core.TransformationsUtil;
+import lombok.core.AST.Kind;
+import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseAST.Node;
@@ -19,30 +22,59 @@ import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.mangosdk.spi.ProviderFor;
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleGetter implements EclipseAnnotationHandler<Getter> {
+ public void generateGetterForField(Node fieldNode, ASTNode pos) {
+ AccessLevel level = Getter.DEFAULT_ACCESS_LEVEL;
+ Node errorNode = fieldNode;
+
+ for ( Node child : fieldNode.down() ) {
+ if ( child.getKind() == Kind.ANNOTATION ) {
+ if ( Eclipse.annotationTypeMatches(Getter.class, child) ) {
+ level = Eclipse.createAnnotation(Getter.class, child).getInstance().value();
+ errorNode = child;
+ pos = child.get();
+ break;
+ }
+ }
+ }
+
+ createGetterForField(level, fieldNode, errorNode, pos);
+ }
+
@Override public boolean handle(AnnotationValues<Getter> annotation, Annotation ast, Node annotationNode) {
- if ( !(annotationNode.up().get() instanceof FieldDeclaration) ) return false;
- FieldDeclaration field = (FieldDeclaration) annotationNode.up().get();
+ Node fieldNode = annotationNode.up();
+ AccessLevel level = annotation.getInstance().value();
+ return createGetterForField(level, fieldNode, annotationNode, annotationNode.get());
+ }
+
+ private boolean createGetterForField(AccessLevel level, Node fieldNode, Node errorNode, ASTNode pos) {
+ if ( fieldNode.getKind() != Kind.FIELD ) {
+ errorNode.addError("@Getter is only supported on a field.");
+ return false;
+ }
+
+ FieldDeclaration field = (FieldDeclaration) fieldNode.get();
TypeReference fieldType = field.type;
String getterName = TransformationsUtil.toGetterName(
new String(field.name), nameEquals(fieldType.getTypeName(), "boolean"));
- TypeDeclaration parent = (TypeDeclaration) annotationNode.up().up().get();
+ TypeDeclaration parent = (TypeDeclaration) fieldNode.up().get();
if ( parent.methods != null ) for ( AbstractMethodDeclaration method : parent.methods ) {
if ( method.selector != null && new String(method.selector).equals(getterName) ) {
- annotationNode.addWarning(String.format(
+ errorNode.addWarning(String.format(
"Not generating %s(): A method with that name already exists", getterName));
return false;
}
}
- int modifier = toModifier(annotation.getInstance().value());
+ int modifier = toModifier(level) | (field.modifiers & ClassFileConstants.AccStatic);
- MethodDeclaration method = generateGetter(parent, field, getterName, modifier, ast);
+ MethodDeclaration method = generateGetter(parent, field, getterName, modifier, pos);
if ( parent.methods == null ) {
parent.methods = new AbstractMethodDeclaration[1];
@@ -58,7 +90,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
}
private MethodDeclaration generateGetter(TypeDeclaration parent, FieldDeclaration field, String name,
- int modifier, Annotation ast) {
+ int modifier, ASTNode pos) {
MethodDeclaration method = new MethodDeclaration(parent.compilationResult);
method.modifiers = modifier;
method.returnType = field.type;
@@ -72,8 +104,8 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
method.bits |= ASTNode.Bit24;
Expression fieldExpression = new SingleNameReference(field.name, (field.declarationSourceStart << 32) | field.declarationSourceEnd);
Statement returnStatement = new ReturnStatement(fieldExpression, field.sourceStart, field.sourceEnd);
- method.bodyStart = method.declarationSourceStart = method.sourceStart = ast.sourceStart;
- method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = ast.sourceEnd;
+ method.bodyStart = method.declarationSourceStart = method.sourceStart = pos.sourceStart;
+ method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = pos.sourceEnd;
method.statements = new Statement[] { returnStatement };
return method;
}
diff --git a/src/lombok/eclipse/handlers/HandleSetter.java b/src/lombok/eclipse/handlers/HandleSetter.java
index 692061e4..d0d0d902 100644
--- a/src/lombok/eclipse/handlers/HandleSetter.java
+++ b/src/lombok/eclipse/handlers/HandleSetter.java
@@ -15,36 +15,65 @@ import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.mangosdk.spi.ProviderFor;
+import lombok.AccessLevel;
import lombok.Setter;
import lombok.core.AnnotationValues;
import lombok.core.TransformationsUtil;
+import lombok.core.AST.Kind;
+import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseAST.Node;
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleSetter implements EclipseAnnotationHandler<Setter> {
+ public void generateSetterForField(Node fieldNode, ASTNode pos) {
+ AccessLevel level = Setter.DEFAULT_ACCESS_LEVEL;
+ Node errorNode = fieldNode;
+
+ for ( Node child : fieldNode.down() ) {
+ if ( child.getKind() == Kind.ANNOTATION ) {
+ if ( Eclipse.annotationTypeMatches(Setter.class, child) ) {
+ level = Eclipse.createAnnotation(Setter.class, child).getInstance().value();
+ errorNode = child;
+ pos = child.get();
+ break;
+ }
+ }
+ }
+
+ createSetterForField(level, fieldNode, errorNode, pos);
+ }
+
@Override public boolean handle(AnnotationValues<Setter> annotation, Annotation ast, Node annotationNode) {
- if ( !(annotationNode.up().get() instanceof FieldDeclaration) ) return false;
- FieldDeclaration field = (FieldDeclaration) annotationNode.up().get();
+ Node fieldNode = annotationNode.up();
+ if ( fieldNode.getKind() != Kind.FIELD ) return false;
+ AccessLevel level = annotation.getInstance().value();
+ return createSetterForField(level, fieldNode, annotationNode, annotationNode.get());
+ }
+
+ private boolean createSetterForField(AccessLevel level, Node fieldNode, Node errorNode, ASTNode pos) {
+ if ( fieldNode.getKind() != Kind.FIELD ) return false;
+ FieldDeclaration field = (FieldDeclaration) fieldNode.get();
String setterName = TransformationsUtil.toSetterName(new String(field.name));
- TypeDeclaration parent = (TypeDeclaration) annotationNode.up().up().get();
+ TypeDeclaration parent = (TypeDeclaration) fieldNode.up().get();
if ( parent.methods != null ) for ( AbstractMethodDeclaration method : parent.methods ) {
if ( method.selector != null && new String(method.selector).equals(setterName) ) {
- annotationNode.addWarning(String.format(
+ errorNode.addWarning(String.format(
"Not generating %s(%s %s): A method with that name already exists",
setterName, field.type, new String(field.name)));
return false;
}
}
- int modifier = toModifier(annotation.getInstance().value());
+ int modifier = toModifier(level) | (field.modifiers & ClassFileConstants.AccStatic);
- MethodDeclaration method = generateSetter(parent, field, setterName, modifier, ast);
+ MethodDeclaration method = generateSetter(parent, field, setterName, modifier, pos);
if ( parent.methods == null ) {
parent.methods = new AbstractMethodDeclaration[1];
@@ -60,7 +89,7 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
}
private MethodDeclaration generateSetter(TypeDeclaration parent, FieldDeclaration field, String name,
- int modifier, Annotation ast) {
+ int modifier, ASTNode ast) {
long pos = (((long)ast.sourceStart) << 32) | ast.sourceEnd;
MethodDeclaration method = new MethodDeclaration(parent.compilationResult);
method.modifiers = modifier;
diff --git a/src/lombok/javac/HandlerLibrary.java b/src/lombok/javac/HandlerLibrary.java
index 05aebf20..f9404668 100644
--- a/src/lombok/javac/HandlerLibrary.java
+++ b/src/lombok/javac/HandlerLibrary.java
@@ -1,13 +1,10 @@
package lombok.javac;
import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
@@ -16,22 +13,13 @@ import javax.annotation.processing.Messager;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
-import lombok.core.AnnotationValues;
import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
import lombok.core.TypeResolver;
-import lombok.core.AnnotationValues.AnnotationValue;
import lombok.core.AnnotationValues.AnnotationValueDecodeFail;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
-import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
-import com.sun.tools.javac.tree.JCTree.JCExpression;
-import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
-import com.sun.tools.javac.tree.JCTree.JCIdent;
-import com.sun.tools.javac.tree.JCTree.JCLiteral;
-import com.sun.tools.javac.tree.JCTree.JCNewArray;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
public class HandlerLibrary {
@@ -53,58 +41,8 @@ public class HandlerLibrary {
this.annotationClass = annotationClass;
}
- private Object calculateGuess(JCExpression expr) {
- if ( expr instanceof JCLiteral ) {
- return ((JCLiteral)expr).value;
- } else if ( expr instanceof JCIdent || expr instanceof JCFieldAccess ) {
- String x = expr.toString();
- if ( x.endsWith(".class") ) x = x.substring(0, x.length() - 6);
- else {
- int idx = x.lastIndexOf('.');
- if ( idx > -1 ) x = x.substring(idx + 1);
- }
- return x;
- } else return null;
- }
-
public boolean handle(final JavacAST.Node node) {
- Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>();
- JCAnnotation anno = (JCAnnotation) node.get();
- List<JCExpression> arguments = anno.getArguments();
- for ( Method m : annotationClass.getDeclaredMethods() ) {
- if ( !Modifier.isPublic(m.getModifiers()) ) continue;
- String name = m.getName();
- List<String> raws = new ArrayList<String>();
- List<Object> guesses = new ArrayList<Object>();
- final List<DiagnosticPosition> positions = new ArrayList<DiagnosticPosition>();
-
- for ( JCExpression arg : arguments ) {
- JCAssign assign = (JCAssign) arg;
- String mName = assign.lhs.toString();
- if ( !mName.equals(name) ) continue;
- JCExpression rhs = assign.rhs;
- if ( rhs instanceof JCNewArray ) {
- List<JCExpression> elems = ((JCNewArray)rhs).elems;
- for ( JCExpression inner : elems ) {
- raws.add(inner.toString());
- guesses.add(calculateGuess(inner));
- positions.add(inner.pos());
- }
- } else {
- raws.add(rhs.toString());
- guesses.add(calculateGuess(rhs));
- positions.add(rhs.pos());
- }
- }
-
- values.put(name, new AnnotationValue(node, raws, guesses) {
- @Override public void setError(String message, int valueIdx) {
- node.addError(message, positions.get(valueIdx));
- }
- });
- }
-
- return handler.handle(new AnnotationValues<T>(annotationClass, values, node), (JCAnnotation)node.get(), node);
+ return handler.handle(Javac.createAnnotation(annotationClass, node), (JCAnnotation)node.get(), node);
}
}
diff --git a/src/lombok/javac/Javac.java b/src/lombok/javac/Javac.java
new file mode 100644
index 00000000..801e7a23
--- /dev/null
+++ b/src/lombok/javac/Javac.java
@@ -0,0 +1,102 @@
+package lombok.javac;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import lombok.core.AnnotationValues;
+import lombok.core.TypeLibrary;
+import lombok.core.TypeResolver;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues.AnnotationValue;
+import lombok.javac.JavacAST.Node;
+
+import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCLiteral;
+import com.sun.tools.javac.tree.JCTree.JCNewArray;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+public class Javac {
+ private Javac() {
+ //prevent instantiation
+ }
+
+ public static boolean annotationTypeMatches(Class<? extends Annotation> type, Node node) {
+ if ( node.getKind() != Kind.ANNOTATION ) return false;
+ String typeName = ((JCAnnotation)node.get()).annotationType.toString();
+
+ TypeLibrary library = new TypeLibrary();
+ library.addType(type.getName());
+ TypeResolver resolver = new TypeResolver(library, node.getPackageDeclaration(), node.getImportStatements());
+ Collection<String> typeMatches = resolver.findTypeMatches(node, typeName);
+
+ for ( String match : typeMatches ) {
+ if ( match.equals(type.getName()) ) return true;
+ }
+
+ return false;
+ }
+
+ public static <A extends Annotation> AnnotationValues<A> createAnnotation(Class<A> type, final Node node) {
+ Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>();
+ JCAnnotation anno = (JCAnnotation) node.get();
+ List<JCExpression> arguments = anno.getArguments();
+ for ( Method m : type.getDeclaredMethods() ) {
+ if ( !Modifier.isPublic(m.getModifiers()) ) continue;
+ String name = m.getName();
+ List<String> raws = new ArrayList<String>();
+ List<Object> guesses = new ArrayList<Object>();
+ final List<DiagnosticPosition> positions = new ArrayList<DiagnosticPosition>();
+
+ for ( JCExpression arg : arguments ) {
+ JCAssign assign = (JCAssign) arg;
+ String mName = assign.lhs.toString();
+ if ( !mName.equals(name) ) continue;
+ JCExpression rhs = assign.rhs;
+ if ( rhs instanceof JCNewArray ) {
+ List<JCExpression> elems = ((JCNewArray)rhs).elems;
+ for ( JCExpression inner : elems ) {
+ raws.add(inner.toString());
+ guesses.add(calculateGuess(inner));
+ positions.add(inner.pos());
+ }
+ } else {
+ raws.add(rhs.toString());
+ guesses.add(calculateGuess(rhs));
+ positions.add(rhs.pos());
+ }
+ }
+
+ values.put(name, new AnnotationValue(node, raws, guesses) {
+ @Override public void setError(String message, int valueIdx) {
+ node.addError(message, positions.get(valueIdx));
+ }
+ });
+ }
+
+ return new AnnotationValues<A>(type, values, node);
+ }
+
+ private static Object calculateGuess(JCExpression expr) {
+ if ( expr instanceof JCLiteral ) {
+ return ((JCLiteral)expr).value;
+ } else if ( expr instanceof JCIdent || expr instanceof JCFieldAccess ) {
+ String x = expr.toString();
+ if ( x.endsWith(".class") ) x = x.substring(0, x.length() - 6);
+ else {
+ int idx = x.lastIndexOf('.');
+ if ( idx > -1 ) x = x.substring(idx + 1);
+ }
+ return x;
+ } else return null;
+ }
+}
diff --git a/src/lombok/javac/handlers/HandleData.java b/src/lombok/javac/handlers/HandleData.java
new file mode 100644
index 00000000..48eb7f76
--- /dev/null
+++ b/src/lombok/javac/handlers/HandleData.java
@@ -0,0 +1,49 @@
+package lombok.javac.handlers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.Data;
+import lombok.core.AnnotationValues;
+import lombok.core.AST.Kind;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacAST.Node;
+
+import org.mangosdk.spi.ProviderFor;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+
+@ProviderFor(JavacAnnotationHandler.class)
+public class HandleData implements JavacAnnotationHandler<Data> {
+ @Override public boolean handle(AnnotationValues<Data> annotation, JCAnnotation ast, Node annotationNode) {
+ Node typeNode = annotationNode.up();
+ JCClassDecl typeDecl = null;
+ if ( typeNode.get() instanceof JCClassDecl ) typeDecl = (JCClassDecl)typeNode.get();
+ long flags = typeDecl.mods.flags;
+ boolean notAClass = (flags & (Flags.INTERFACE | Flags.ENUM | Flags.ANNOTATION)) != 0;
+
+ if ( typeDecl != null || notAClass ) {
+ annotationNode.addError("@Data is only supported on a class.");
+ return false;
+ }
+
+ List<Node> nodesForEquality = new ArrayList<Node>();
+ for ( Node child : typeNode.down() ) {
+ if ( child.getKind() != Kind.FIELD ) continue;
+ JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
+ long fieldFlags = fieldDecl.mods.flags;
+ //Skip static fields.
+ if ( (fieldFlags & Flags.STATIC) != 0 ) continue;
+ if ( (fieldFlags & Flags.TRANSIENT) == 0 ) nodesForEquality.add(child);
+ new HandleGetter().generateGetterForField(child, annotationNode.get());
+ if ( (fieldFlags & Flags.FINAL) == 0 )
+ new HandleSetter().generateSetterForField(child, annotationNode.get());
+ }
+
+ //TODO generate constructor, hashCode, equals, toString.
+ return true;
+ }
+}
diff --git a/src/lombok/javac/handlers/HandleGetter.java b/src/lombok/javac/handlers/HandleGetter.java
index 5cc2c108..651bc018 100644
--- a/src/lombok/javac/handlers/HandleGetter.java
+++ b/src/lombok/javac/handlers/HandleGetter.java
@@ -2,14 +2,17 @@ package lombok.javac.handlers;
import static lombok.javac.handlers.PKG.*;
+import lombok.AccessLevel;
import lombok.Getter;
import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
+import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
-import lombok.javac.JavacAST;
+import lombok.javac.JavacAST.Node;
import org.mangosdk.spi.ProviderFor;
+import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCBlock;
@@ -21,35 +24,59 @@ import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@ProviderFor(JavacAnnotationHandler.class)
public class HandleGetter implements JavacAnnotationHandler<Getter> {
- @Override public boolean handle(AnnotationValues<Getter> annotation, JCAnnotation ast, JavacAST.Node annotationNode) {
- if ( annotationNode.up().getKind() != Kind.FIELD ) {
- annotationNode.addError("@Getter is only supported on a field.");
+ public void generateGetterForField(Node fieldNode, DiagnosticPosition pos) {
+ AccessLevel level = Getter.DEFAULT_ACCESS_LEVEL;
+ Node errorNode = fieldNode;
+
+ for ( Node child : fieldNode.down() ) {
+ if ( child.getKind() == Kind.ANNOTATION ) {
+ if ( Javac.annotationTypeMatches(Getter.class, child) ) {
+ level = Javac.createAnnotation(Getter.class, child).getInstance().value();
+ errorNode = child;
+ pos = child.get();
+ break;
+ }
+ }
+ }
+
+ createGetterForField(level, fieldNode, errorNode, pos);
+ }
+
+ @Override public boolean handle(AnnotationValues<Getter> annotation, JCAnnotation ast, Node annotationNode) {
+ Node fieldNode = annotationNode.up();
+ AccessLevel level = annotation.getInstance().value();
+ return createGetterForField(level, fieldNode, annotationNode, annotationNode.get());
+ }
+
+ private boolean createGetterForField(AccessLevel level, Node fieldNode, Node errorNode, DiagnosticPosition pos) {
+ if ( fieldNode.getKind() != Kind.FIELD ) {
+ errorNode.addError("@Getter is only supported on a field.");
return false;
}
- String methodName = toGetterName((JCVariableDecl) annotationNode.up().get());
+ JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get();
+ String methodName = toGetterName(fieldDecl);
- if ( methodExists(methodName, annotationNode.up()) ) {
- annotationNode.addWarning(
+ if ( methodExists(methodName, fieldNode) ) {
+ errorNode.addWarning(
String.format("Not generating %s(): A method with that name already exists", methodName));
return false;
}
- Getter getter = annotation.getInstance();
-
- JCClassDecl javacClassTree = (JCClassDecl) annotationNode.up().up().get();
+ JCClassDecl javacClassTree = (JCClassDecl) fieldNode.up().get();
- int access = toJavacModifier(getter.value());
+ long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
- JCMethodDecl getterMethod = createGetter(access, annotationNode.up(), annotationNode.getTreeMaker());
+ JCMethodDecl getterMethod = createGetter(access, fieldNode, fieldNode.getTreeMaker());
javacClassTree.defs = javacClassTree.defs.append(getterMethod);
return true;
}
- private JCMethodDecl createGetter(int access, JavacAST.Node field, TreeMaker treeMaker) {
+ private JCMethodDecl createGetter(long access, Node field, TreeMaker treeMaker) {
JCVariableDecl fieldNode = (JCVariableDecl) field.get();
JCStatement returnStatement = treeMaker.Return(treeMaker.Ident(fieldNode.getName()));
diff --git a/src/lombok/javac/handlers/HandleSetter.java b/src/lombok/javac/handlers/HandleSetter.java
index da4e9ff0..f1e73489 100644
--- a/src/lombok/javac/handlers/HandleSetter.java
+++ b/src/lombok/javac/handlers/HandleSetter.java
@@ -1,15 +1,18 @@
package lombok.javac.handlers;
import static lombok.javac.handlers.PKG.*;
+import lombok.AccessLevel;
import lombok.Setter;
import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
+import lombok.javac.Javac;
import lombok.javac.JavacAST;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacAST.Node;
import org.mangosdk.spi.ProviderFor;
+import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCAssign;
@@ -23,37 +26,60 @@ import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@ProviderFor(JavacAnnotationHandler.class)
public class HandleSetter implements JavacAnnotationHandler<Setter> {
+ public void generateSetterForField(Node fieldNode, DiagnosticPosition pos) {
+ AccessLevel level = Setter.DEFAULT_ACCESS_LEVEL;
+ Node errorNode = fieldNode;
+
+ for ( Node child : fieldNode.down() ) {
+ if ( child.getKind() == Kind.ANNOTATION ) {
+ if ( Javac.annotationTypeMatches(Setter.class, child) ) {
+ level = Javac.createAnnotation(Setter.class, child).getInstance().value();
+ errorNode = child;
+ pos = child.get();
+ break;
+ }
+ }
+ }
+
+ createSetterForField(level, fieldNode, errorNode, pos);
+ }
+
@Override public boolean handle(AnnotationValues<Setter> annotation, JCAnnotation ast, Node annotationNode) {
- if ( annotationNode.up().getKind() != Kind.FIELD ) {
- annotationNode.addError("@Setter is only supported on a field.");
+ Node fieldNode = annotationNode.up();
+ AccessLevel level = annotation.getInstance().value();
+ return createSetterForField(level, fieldNode, annotationNode, annotationNode.get());
+ }
+
+ private boolean createSetterForField(AccessLevel level, Node fieldNode, Node errorNode, DiagnosticPosition pos) {
+ if ( fieldNode.getKind() != Kind.FIELD ) {
+ fieldNode.addError("@Setter is only supported on a field.");
return false;
}
- JCVariableDecl fieldNode = (JCVariableDecl) annotationNode.up().get();
- String methodName = toSetterName(fieldNode);
+ JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get();
+ String methodName = toSetterName(fieldDecl);
- if ( methodExists(methodName, annotationNode.up()) ) {
- annotationNode.addWarning(
+ if ( methodExists(methodName, fieldNode) ) {
+ errorNode.addWarning(
String.format("Not generating %s(%s %s): A method with that name already exists",
- methodName, fieldNode.vartype, fieldNode.name));
+ methodName, fieldDecl.vartype, fieldDecl.name));
return false;
}
- Setter setter = annotation.getInstance();
-
- JCClassDecl javacClassTree = (JCClassDecl) annotationNode.up().up().get();
+ JCClassDecl javacClassTree = (JCClassDecl) fieldNode.up().get();
- int access = toJavacModifier(setter.value());
+ long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
- JCMethodDecl setterMethod = createSetter(access, annotationNode.up(), annotationNode.getTreeMaker());
+ JCMethodDecl setterMethod = createSetter(access, fieldNode, fieldNode.getTreeMaker());
javacClassTree.defs = javacClassTree.defs.append(setterMethod);
return true;
}
- private JCMethodDecl createSetter(int access, JavacAST.Node field, TreeMaker treeMaker) {
+ private JCMethodDecl createSetter(long access, JavacAST.Node field, TreeMaker treeMaker) {
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
JCFieldAccess thisX = treeMaker.Select(treeMaker.Ident(field.toName("this")), fieldDecl.name);