mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 14:16:11 +00:00
Added initial support for the @Data annotation. Currently produces getters and setters only,
not yet a constructor, toString, hashCode, or equals. HandleGetter and HandleSetter have been updated to handle static (theoretic; you can't put annotations on static fields normally). You can now make AnnotationValue objects using just an annotationNode and a target type, as well as check if a given annotationNode is likely to represent a target annotation type. This is in Javac and Eclipse classes. HandleGetter and HandleSetter can now be asked to make a getter/setter, and will grab access level off of a Getter/Setter annotation, if present.
This commit is contained in:
1 parent
e56ab6c245
commit
ff306fa5d9
13 files changed
+506
-195
No files matched your search
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) fieldNode.up().get();
|
||||
|
||||
JCClassDecl javacClassTree = (JCClassDecl) annotationNode.up().up().get();
|
||||
long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
|
||||
|
||||
int access = toJavacModifier(getter.value());
|
||||
|
||||
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()));
|
||||
|
||||
|
||||
@@ -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) fieldNode.up().get();
|
||||
|
||||
JCClassDecl javacClassTree = (JCClassDecl) annotationNode.up().up().get();
|
||||
long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
|
||||
|
||||
int access = toJavacModifier(setter.value());
|
||||
|
||||
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);
|
||||
|
||||
Reference in new issue
Block a user