aboutsummaryrefslogtreecommitdiff
path: root/src/lombok/javac
diff options
context:
space:
mode:
Diffstat (limited to 'src/lombok/javac')
-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
5 files changed, 231 insertions, 89 deletions
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);