mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 06:15:41 +00:00
toString(), equals(), and hashCode() now use getX() instead of x if either it exists OR it will be generated by some other lombok annotation, addressing issue #110.
code deduplication by removing HandleData's scanning for fields, which is now no longer done; the sub-parts of Data (Getter, Setter, RequiredArgsConstructor, etc) take care of it now. fix for class-level @Getter/@Setter, which used to go for every field. Now they skip the usual fields (static, for setters final, and $ prefixed fields). Bugfix for @Data not recognizing that it should let field-level @Getter/@Setter take care of generating the getter/setter for multi field declarations (@Getter int x, y);
This commit is contained in:
1 parent
868d8b0f93
commit
ceda2e5efe
14 files changed
+367
-253
No files matched your search
@@ -233,7 +233,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
case STATEMENT:
|
||||
return buildStatement((Statement) node);
|
||||
case ANNOTATION:
|
||||
return buildAnnotation((Annotation) node);
|
||||
return buildAnnotation((Annotation) node, false);
|
||||
default:
|
||||
throw new AssertionError("Did not expect to arrive here: " + kind);
|
||||
}
|
||||
@@ -261,7 +261,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
childNodes.addAll(buildFields(type.fields));
|
||||
childNodes.addAll(buildTypes(type.memberTypes));
|
||||
childNodes.addAll(buildMethods(type.methods));
|
||||
childNodes.addAll(buildAnnotations(type.annotations));
|
||||
childNodes.addAll(buildAnnotations(type.annotations, false));
|
||||
return putInMap(new EclipseNode(this, type, childNodes, Kind.TYPE));
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
if (setAndGetAsHandled(field)) return null;
|
||||
List<EclipseNode> childNodes = new ArrayList<EclipseNode>();
|
||||
addIfNotNull(childNodes, buildStatement(field.initialization));
|
||||
childNodes.addAll(buildAnnotations(field.annotations));
|
||||
childNodes.addAll(buildAnnotations(field.annotations, true));
|
||||
return putInMap(new EclipseNode(this, field, childNodes, Kind.FIELD));
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
List<EclipseNode> childNodes = new ArrayList<EclipseNode>();
|
||||
childNodes.addAll(buildArguments(method.arguments));
|
||||
childNodes.addAll(buildStatements(method.statements));
|
||||
childNodes.addAll(buildAnnotations(method.annotations));
|
||||
childNodes.addAll(buildAnnotations(method.annotations, false));
|
||||
return putInMap(new EclipseNode(this, method, childNodes, Kind.METHOD));
|
||||
}
|
||||
|
||||
@@ -319,19 +319,23 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
if (setAndGetAsHandled(local)) return null;
|
||||
List<EclipseNode> childNodes = new ArrayList<EclipseNode>();
|
||||
addIfNotNull(childNodes, buildStatement(local.initialization));
|
||||
childNodes.addAll(buildAnnotations(local.annotations));
|
||||
childNodes.addAll(buildAnnotations(local.annotations, true));
|
||||
return putInMap(new EclipseNode(this, local, childNodes, kind));
|
||||
}
|
||||
|
||||
private Collection<EclipseNode> buildAnnotations(Annotation[] annotations) {
|
||||
private Collection<EclipseNode> buildAnnotations(Annotation[] annotations, boolean varDecl) {
|
||||
List<EclipseNode> elements = new ArrayList<EclipseNode>();
|
||||
if (annotations != null) for (Annotation an : annotations) addIfNotNull(elements, buildAnnotation(an));
|
||||
if (annotations != null) for (Annotation an : annotations) addIfNotNull(elements, buildAnnotation(an, varDecl));
|
||||
return elements;
|
||||
}
|
||||
|
||||
private EclipseNode buildAnnotation(Annotation annotation) {
|
||||
private EclipseNode buildAnnotation(Annotation annotation, boolean field) {
|
||||
if (annotation == null) return null;
|
||||
if (setAndGetAsHandled(annotation)) return null;
|
||||
boolean handled = setAndGetAsHandled(annotation);
|
||||
if (!field && handled) {
|
||||
// @Foo int x, y; is handled in eclipse by putting the same annotation node on 2 FieldDeclarations.
|
||||
return null;
|
||||
}
|
||||
return putInMap(new EclipseNode(this, annotation, null, Kind.ANNOTATION));
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
package lombok.eclipse.handlers;
|
||||
|
||||
import static lombok.eclipse.Eclipse.fromQualifiedName;
|
||||
import static lombok.eclipse.Eclipse.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -29,7 +29,10 @@ import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.handlers.TransformationsUtil;
|
||||
import lombok.eclipse.Eclipse;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
@@ -99,7 +102,17 @@ public class EclipseHandlerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static AbstractMethodDeclaration findGetter(EclipseNode field) {
|
||||
private static class GetterMethod {
|
||||
private final char[] name;
|
||||
private final TypeReference type;
|
||||
|
||||
GetterMethod(char[] name, TypeReference type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private static GetterMethod findGetter(EclipseNode field) {
|
||||
TypeReference fieldType = ((FieldDeclaration)field.get()).type;
|
||||
boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0;
|
||||
EclipseNode typeNode = field.up();
|
||||
@@ -109,33 +122,68 @@ public class EclipseHandlerUtil {
|
||||
case EXISTS_BY_USER:
|
||||
for (EclipseNode potentialGetter : typeNode.down()) {
|
||||
if (potentialGetter.getKind() != Kind.METHOD) continue;
|
||||
AbstractMethodDeclaration method = (AbstractMethodDeclaration) potentialGetter.get();
|
||||
if (!(potentialGetter.get() instanceof MethodDeclaration)) continue;
|
||||
MethodDeclaration method = (MethodDeclaration) potentialGetter.get();
|
||||
if (!potentialGetterName.equals(new String(method.selector))) continue;
|
||||
/** static getX() methods don't count. */
|
||||
if ((method.modifiers & ClassFileConstants.AccStatic) != 0) continue;
|
||||
/** Nor do getters with a non-empty parameter list. */
|
||||
if (method.arguments != null && method.arguments.length > 0) continue;
|
||||
return method;
|
||||
return new GetterMethod(method.selector, method.returnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the field has a @Getter annotation.
|
||||
|
||||
boolean hasGetterAnnotation = false;
|
||||
|
||||
for (EclipseNode child : field.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
|
||||
AnnotationValues<Getter> ann = Eclipse.createAnnotation(Getter.class, child);
|
||||
if (ann.getInstance().value() == AccessLevel.NONE) return null; //Definitely WONT have a getter.
|
||||
hasGetterAnnotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the class has a @Getter annotation.
|
||||
|
||||
if (!hasGetterAnnotation && new HandleGetter().fieldQualifiesForGetterGeneration(field)) {
|
||||
//Check if the class has @Getter or @Data annotation.
|
||||
|
||||
EclipseNode containingType = field.up();
|
||||
if (containingType != null) for (EclipseNode child : containingType.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Data.class, child)) hasGetterAnnotation = true;
|
||||
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
|
||||
AnnotationValues<Getter> ann = Eclipse.createAnnotation(Getter.class, child);
|
||||
if (ann.getInstance().value() == AccessLevel.NONE) return null; //Definitely WONT have a getter.
|
||||
hasGetterAnnotation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasGetterAnnotation) {
|
||||
String getterName = TransformationsUtil.toGetterName(field.getName(), isBoolean);
|
||||
return new GetterMethod(getterName.toCharArray(), fieldType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static TypeReference getFieldType(EclipseNode field, boolean useFieldsDirectly) {
|
||||
AbstractMethodDeclaration getter = useFieldsDirectly ? null : findGetter(field);
|
||||
if (!(getter instanceof MethodDeclaration)) {
|
||||
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
|
||||
if (getter == null) {
|
||||
return ((FieldDeclaration)field.get()).type;
|
||||
}
|
||||
|
||||
return ((MethodDeclaration)getter).returnType;
|
||||
return getter.type;
|
||||
}
|
||||
|
||||
static Expression createFieldAccessor(EclipseNode field, boolean useFieldsDirectly, ASTNode source) {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long)pS << 32 | pE;
|
||||
|
||||
AbstractMethodDeclaration getter = useFieldsDirectly ? null : findGetter(field);
|
||||
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
|
||||
|
||||
if (getter == null) {
|
||||
FieldReference thisX = new FieldReference(field.getName().toCharArray(), p);
|
||||
@@ -150,7 +198,7 @@ public class EclipseHandlerUtil {
|
||||
call.sourceStart = pS; call.sourceEnd = pE;
|
||||
call.receiver = new ThisReference(pS, pE);
|
||||
Eclipse.setGeneratedBy(call.receiver, source);
|
||||
call.selector = getter.selector;
|
||||
call.selector = getter.name;
|
||||
return call;
|
||||
}
|
||||
|
||||
@@ -158,7 +206,7 @@ public class EclipseHandlerUtil {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long)pS << 32 | pE;
|
||||
|
||||
AbstractMethodDeclaration getter = useFieldsDirectly ? null : findGetter(field);
|
||||
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
|
||||
|
||||
if (getter == null) {
|
||||
NameReference ref;
|
||||
@@ -178,7 +226,7 @@ public class EclipseHandlerUtil {
|
||||
call.sourceStart = pS; call.sourceEnd = pE;
|
||||
call.receiver = new SingleNameReference(receiver, p);
|
||||
Eclipse.setGeneratedBy(call.receiver, source);
|
||||
call.selector = getter.selector;
|
||||
call.selector = getter.name;
|
||||
return call;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public class HandleConstructor {
|
||||
String staticName = ann.staticName();
|
||||
if (level == AccessLevel.NONE) return true;
|
||||
List<EclipseNode> fields = new ArrayList<EclipseNode>();
|
||||
new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, false, ast);
|
||||
new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, false, ast);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -95,23 +95,27 @@ public class HandleConstructor {
|
||||
@SuppressWarnings("deprecation")
|
||||
boolean suppressConstructorProperties = ann.suppressConstructorProperties();
|
||||
if (level == AccessLevel.NONE) return true;
|
||||
List<EclipseNode> fields = new ArrayList<EclipseNode>();
|
||||
for (EclipseNode child : typeNode.down()) {
|
||||
if (child.getKind() != Kind.FIELD) continue;
|
||||
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') continue;
|
||||
//Skip static fields.
|
||||
if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue;
|
||||
boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0;
|
||||
boolean isNonNull = findAnnotations(fieldDecl, TransformationsUtil.NON_NULL_PATTERN).length != 0;
|
||||
if ((isFinal || isNonNull) && fieldDecl.initialization == null) fields.add(child);
|
||||
}
|
||||
new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, suppressConstructorProperties, ast);
|
||||
new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, false, suppressConstructorProperties, ast);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<EclipseNode> findRequiredFields(EclipseNode typeNode) {
|
||||
List<EclipseNode> fields = new ArrayList<EclipseNode>();
|
||||
for (EclipseNode child : typeNode.down()) {
|
||||
if (child.getKind() != Kind.FIELD) continue;
|
||||
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') continue;
|
||||
//Skip static fields.
|
||||
if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue;
|
||||
boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0;
|
||||
boolean isNonNull = findAnnotations(fieldDecl, TransformationsUtil.NON_NULL_PATTERN).length != 0;
|
||||
if ((isFinal || isNonNull) && fieldDecl.initialization == null) fields.add(child);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
public static class HandleAllArgsConstructor implements EclipseAnnotationHandler<AllArgsConstructor> {
|
||||
@Override public boolean handle(AnnotationValues<AllArgsConstructor> annotation, Annotation ast, EclipseNode annotationNode) {
|
||||
@@ -132,12 +136,16 @@ public class HandleConstructor {
|
||||
if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue;
|
||||
fields.add(child);
|
||||
}
|
||||
new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, suppressConstructorProperties, ast);
|
||||
new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, suppressConstructorProperties, ast);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void generateConstructor(AccessLevel level, EclipseNode typeNode, List<EclipseNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, ASTNode source) {
|
||||
public void generateRequiredArgsConstructor(EclipseNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists, ASTNode source) {
|
||||
generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, false, source);
|
||||
}
|
||||
|
||||
public void generateConstructor(EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, ASTNode source) {
|
||||
if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return;
|
||||
if (skipIfConstructorExists) {
|
||||
for (EclipseNode child : typeNode.down()) {
|
||||
|
||||
@@ -21,23 +21,13 @@
|
||||
*/
|
||||
package lombok.eclipse.handlers;
|
||||
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.findAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.handlers.TransformationsUtil;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
|
||||
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;
|
||||
@@ -62,37 +52,18 @@ public class HandleData implements EclipseAnnotationHandler<Data> {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<EclipseNode> nodesForConstructor = new ArrayList<EclipseNode>();
|
||||
Map<EclipseNode, Boolean> gettersAndSetters = new LinkedHashMap<EclipseNode, Boolean>();
|
||||
for (EclipseNode child : typeNode.down()) {
|
||||
if (child.getKind() != Kind.FIELD) continue;
|
||||
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') continue;
|
||||
//Skip static fields.
|
||||
if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue;
|
||||
boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0;
|
||||
boolean isNonNull = findAnnotations(fieldDecl, TransformationsUtil.NON_NULL_PATTERN).length != 0;
|
||||
if ((isFinal || isNonNull) && fieldDecl.initialization == null) nodesForConstructor.add(child);
|
||||
gettersAndSetters.put(child, !isFinal);
|
||||
}
|
||||
|
||||
//Careful: Generate the public static constructor (if there is one) LAST, so that any attempt to
|
||||
//'find callers' on the annotation node will find callers of the constructor, which is by far the
|
||||
//most useful of the many methods built by @Data. This trick won't work for the non-static constructor,
|
||||
//for whatever reason, though you can find callers of that one by focusing on the class name itself
|
||||
//and hitting 'find callers'.
|
||||
|
||||
new HandleConstructor().generateConstructor(AccessLevel.PUBLIC, typeNode, nodesForConstructor, ann.staticConstructor(), true, false, ast);
|
||||
|
||||
for (Map.Entry<EclipseNode, Boolean> field : gettersAndSetters.entrySet()) {
|
||||
new HandleGetter().generateGetterForField(field.getKey(), annotationNode.get(), AccessLevel.PUBLIC, true);
|
||||
if (field.getValue()) new HandleSetter().generateSetterForField(field.getKey(), annotationNode.get(), AccessLevel.PUBLIC, true);
|
||||
}
|
||||
|
||||
new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
|
||||
new HandleSetter().generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
|
||||
new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);
|
||||
new HandleToString().generateToStringForType(typeNode, annotationNode);
|
||||
|
||||
new HandleConstructor().generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, ast);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,45 @@ import org.mangosdk.spi.ProviderFor;
|
||||
*/
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
public class HandleGetter implements EclipseAnnotationHandler<Getter> {
|
||||
public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter) {
|
||||
if (checkForTypeLevelGetter) {
|
||||
if (typeNode != null) for (EclipseNode child : typeNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (annotationTypeMatches(Getter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
pos.addError("@Getter is only supported on a class or a field.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EclipseNode field : typeNode.down()) {
|
||||
if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, pos.get(), level);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean fieldQualifiesForGetterGeneration(EclipseNode field) {
|
||||
if (field.getKind() != Kind.FIELD) return false;
|
||||
FieldDeclaration fieldDecl = (FieldDeclaration) field.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') return false;
|
||||
//Skip static fields.
|
||||
if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a getter on the stated field.
|
||||
*
|
||||
@@ -65,7 +104,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
|
||||
* If not, the getter is still generated if it isn't already there, though there will not
|
||||
* be a warning if its already there. The default access level is used.
|
||||
*/
|
||||
public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, boolean checkForTypeLevelGetter) {
|
||||
public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level) {
|
||||
for (EclipseNode child : fieldNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (annotationTypeMatches(Getter.class, child)) {
|
||||
@@ -75,18 +114,6 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForTypeLevelGetter) {
|
||||
EclipseNode containingType = fieldNode.up();
|
||||
if (containingType != null) for (EclipseNode child : containingType.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (annotationTypeMatches(Getter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createGetterForField(level, fieldNode, fieldNode, pos, false);
|
||||
}
|
||||
|
||||
@@ -100,22 +127,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
|
||||
return createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true);
|
||||
}
|
||||
if (node.getKind() == Kind.TYPE) {
|
||||
TypeDeclaration typeDecl = null;
|
||||
if (node.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) node.get();
|
||||
int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
|
||||
boolean notAClass = (modifiers &
|
||||
(ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
annotationNode.addError("@Getter is only supported on a class.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EclipseNode field : node.down()) {
|
||||
if (field.getKind() != Kind.FIELD) continue;
|
||||
generateGetterForField(field, ast, level, false);
|
||||
}
|
||||
return true;
|
||||
return generateGetterForType(node, annotationNode, level, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -130,7 +142,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
|
||||
private boolean createGetterForField(AccessLevel level,
|
||||
EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists) {
|
||||
if (fieldNode.getKind() != Kind.FIELD) {
|
||||
errorNode.addError("@Getter is only supported on a field.");
|
||||
errorNode.addError("@Getter is only supported on a class or a field.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,44 @@ import org.mangosdk.spi.ProviderFor;
|
||||
*/
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
public class HandleSetter implements EclipseAnnotationHandler<Setter> {
|
||||
public boolean generateSetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelSetter) {
|
||||
if (checkForTypeLevelSetter) {
|
||||
if (typeNode != null) for (EclipseNode child : typeNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (annotationTypeMatches(Setter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
pos.addError("@Setter is only supported on a class or a field.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EclipseNode field : typeNode.down()) {
|
||||
if (field.getKind() != Kind.FIELD) continue;
|
||||
FieldDeclaration fieldDecl = (FieldDeclaration) field.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') continue;
|
||||
//Skip static fields.
|
||||
if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue;
|
||||
//Skip final fields.
|
||||
if ((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0) continue;
|
||||
|
||||
generateSetterForField(field, pos.get(), level);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a setter on the stated field.
|
||||
*
|
||||
@@ -70,7 +108,7 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
|
||||
* If not, the setter is still generated if it isn't already there, though there will not
|
||||
* be a warning if its already there. The default access level is used.
|
||||
*/
|
||||
public void generateSetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, boolean checkForTypeLevelSetter) {
|
||||
public void generateSetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level) {
|
||||
for (EclipseNode child : fieldNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (annotationTypeMatches(Setter.class, child)) {
|
||||
@@ -80,18 +118,6 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForTypeLevelSetter) {
|
||||
EclipseNode containingType = fieldNode.up();
|
||||
if (containingType != null) for (EclipseNode child : containingType.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (annotationTypeMatches(Setter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createSetterForField(level, fieldNode, fieldNode, pos, false);
|
||||
}
|
||||
|
||||
@@ -105,22 +131,7 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
|
||||
return createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true);
|
||||
}
|
||||
if (node.getKind() == Kind.TYPE) {
|
||||
TypeDeclaration typeDecl = null;
|
||||
if (node.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) node.get();
|
||||
int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
|
||||
boolean notAClass = (modifiers &
|
||||
(ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
annotationNode.addError("@Setter is only supported on a class.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EclipseNode field : node.down()) {
|
||||
if (field.getKind() != Kind.FIELD) continue;
|
||||
generateSetterForField(field, ast, level, false);
|
||||
}
|
||||
return true;
|
||||
return generateSetterForType(node, annotationNode, level, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -135,7 +146,7 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
|
||||
private boolean createSetterForField(AccessLevel level,
|
||||
EclipseNode fieldNode, EclipseNode errorNode, ASTNode pos, boolean whineIfExists) {
|
||||
if (fieldNode.getKind() != Kind.FIELD) {
|
||||
errorNode.addError("@Setter is only supported on a field.");
|
||||
errorNode.addError("@Setter is only supported on a class or a field.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
|
||||
case STATEMENT:
|
||||
return buildStatementOrExpression(node);
|
||||
case ANNOTATION:
|
||||
return buildAnnotation((JCAnnotation) node);
|
||||
return buildAnnotation((JCAnnotation) node, false);
|
||||
default:
|
||||
throw new AssertionError("Did not expect: " + kind);
|
||||
}
|
||||
@@ -176,7 +176,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
|
||||
if (setAndGetAsHandled(type)) return null;
|
||||
List<JavacNode> childNodes = new ArrayList<JavacNode>();
|
||||
|
||||
for (JCAnnotation annotation : type.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation));
|
||||
for (JCAnnotation annotation : type.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation, false));
|
||||
for (JCTree def : type.defs) {
|
||||
/* A def can be:
|
||||
* JCClassDecl for inner types
|
||||
@@ -196,7 +196,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
|
||||
private JavacNode buildField(JCVariableDecl field) {
|
||||
if (setAndGetAsHandled(field)) return null;
|
||||
List<JavacNode> childNodes = new ArrayList<JavacNode>();
|
||||
for (JCAnnotation annotation : field.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation));
|
||||
for (JCAnnotation annotation : field.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation, true));
|
||||
addIfNotNull(childNodes, buildExpression(field.init));
|
||||
return putInMap(new JavacNode(this, field, childNodes, Kind.FIELD));
|
||||
}
|
||||
@@ -204,7 +204,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
|
||||
private JavacNode buildLocalVar(JCVariableDecl local, Kind kind) {
|
||||
if (setAndGetAsHandled(local)) return null;
|
||||
List<JavacNode> childNodes = new ArrayList<JavacNode>();
|
||||
for (JCAnnotation annotation : local.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation));
|
||||
for (JCAnnotation annotation : local.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation, true));
|
||||
addIfNotNull(childNodes, buildExpression(local.init));
|
||||
return putInMap(new JavacNode(this, local, childNodes, kind));
|
||||
}
|
||||
@@ -219,7 +219,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
|
||||
private JavacNode buildMethod(JCMethodDecl method) {
|
||||
if (setAndGetAsHandled(method)) return null;
|
||||
List<JavacNode> childNodes = new ArrayList<JavacNode>();
|
||||
for (JCAnnotation annotation : method.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation));
|
||||
for (JCAnnotation annotation : method.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation, false));
|
||||
for (JCVariableDecl param : method.params) addIfNotNull(childNodes, buildLocalVar(param, Kind.ARGUMENT));
|
||||
if (method.body != null && method.body.stats != null) {
|
||||
for (JCStatement statement : method.body.stats) addIfNotNull(childNodes, buildStatement(statement));
|
||||
@@ -227,8 +227,13 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
|
||||
return putInMap(new JavacNode(this, method, childNodes, Kind.METHOD));
|
||||
}
|
||||
|
||||
private JavacNode buildAnnotation(JCAnnotation annotation) {
|
||||
if (setAndGetAsHandled(annotation)) return null;
|
||||
private JavacNode buildAnnotation(JCAnnotation annotation, boolean varDecl) {
|
||||
boolean handled = setAndGetAsHandled(annotation);
|
||||
if (!varDecl && handled) {
|
||||
// @Foo int x, y; is handled in javac by putting the same annotation node on 2 JCVariableDecls.
|
||||
return null;
|
||||
}
|
||||
|
||||
return putInMap(new JavacNode(this, annotation, null, Kind.ANNOTATION));
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public class HandleConstructor {
|
||||
String staticName = ann.staticName();
|
||||
if (level == AccessLevel.NONE) return true;
|
||||
List<JavacNode> fields = List.nil();
|
||||
new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, false);
|
||||
new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -82,24 +82,28 @@ public class HandleConstructor {
|
||||
@SuppressWarnings("deprecation")
|
||||
boolean suppressConstructorProperties = ann.suppressConstructorProperties();
|
||||
if (level == AccessLevel.NONE) return true;
|
||||
List<JavacNode> fields = List.nil();
|
||||
for (JavacNode child : typeNode.down()) {
|
||||
if (child.getKind() != Kind.FIELD) continue;
|
||||
JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.toString().startsWith("$")) continue;
|
||||
long fieldFlags = fieldDecl.mods.flags;
|
||||
//Skip static fields.
|
||||
if ((fieldFlags & Flags.STATIC) != 0) continue;
|
||||
boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
|
||||
boolean isNonNull = !findAnnotations(child, TransformationsUtil.NON_NULL_PATTERN).isEmpty();
|
||||
if ((isFinal || isNonNull) && fieldDecl.init == null) fields = fields.append(child);
|
||||
}
|
||||
new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, suppressConstructorProperties);
|
||||
new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, false, suppressConstructorProperties);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<JavacNode> findRequiredFields(JavacNode typeNode) {
|
||||
List<JavacNode> fields = List.nil();
|
||||
for (JavacNode child : typeNode.down()) {
|
||||
if (child.getKind() != Kind.FIELD) continue;
|
||||
JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.toString().startsWith("$")) continue;
|
||||
long fieldFlags = fieldDecl.mods.flags;
|
||||
//Skip static fields.
|
||||
if ((fieldFlags & Flags.STATIC) != 0) continue;
|
||||
boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
|
||||
boolean isNonNull = !findAnnotations(child, TransformationsUtil.NON_NULL_PATTERN).isEmpty();
|
||||
if ((isFinal || isNonNull) && fieldDecl.init == null) fields = fields.append(child);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
public static class HandleAllArgsConstructor implements JavacAnnotationHandler<AllArgsConstructor> {
|
||||
@Override public boolean handle(AnnotationValues<AllArgsConstructor> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
@@ -123,12 +127,16 @@ public class HandleConstructor {
|
||||
if ((fieldFlags & Flags.STATIC) != 0) continue;
|
||||
fields = fields.append(child);
|
||||
}
|
||||
new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, suppressConstructorProperties);
|
||||
new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, suppressConstructorProperties);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void generateConstructor(AccessLevel level, JavacNode typeNode, List<JavacNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties) {
|
||||
public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists) {
|
||||
generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, false);
|
||||
}
|
||||
|
||||
public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JavacNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties) {
|
||||
if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return;
|
||||
if (skipIfConstructorExists) {
|
||||
for (JavacNode child : typeNode.down()) {
|
||||
|
||||
@@ -21,16 +21,10 @@
|
||||
*/
|
||||
package lombok.javac.handlers;
|
||||
|
||||
import static lombok.javac.handlers.JavacHandlerUtil.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static lombok.javac.handlers.JavacHandlerUtil.markAnnotationAsProcessed;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.handlers.TransformationsUtil;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
import lombok.javac.JavacNode;
|
||||
|
||||
@@ -39,8 +33,6 @@ 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;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
/**
|
||||
* Handles the {@code lombok.Data} annotation for javac.
|
||||
@@ -60,31 +52,12 @@ public class HandleData implements JavacAnnotationHandler<Data> {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<JavacNode> nodesForConstructor = List.nil();
|
||||
Map<JavacNode, Boolean> gettersAndSetters = new LinkedHashMap<JavacNode, Boolean>();
|
||||
for (JavacNode child : typeNode.down()) {
|
||||
if (child.getKind() != Kind.FIELD) continue;
|
||||
JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.toString().startsWith("$")) continue;
|
||||
long fieldFlags = fieldDecl.mods.flags;
|
||||
//Skip static fields.
|
||||
if ((fieldFlags & Flags.STATIC) != 0) continue;
|
||||
boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
|
||||
boolean isNonNull = !findAnnotations(child, TransformationsUtil.NON_NULL_PATTERN).isEmpty();
|
||||
if ((isFinal || isNonNull) && fieldDecl.init == null) nodesForConstructor = nodesForConstructor.append(child);
|
||||
gettersAndSetters.put(child, !isFinal);
|
||||
}
|
||||
|
||||
String staticConstructorName = annotation.getInstance().staticConstructor();
|
||||
|
||||
new HandleConstructor().generateConstructor(AccessLevel.PUBLIC, typeNode, nodesForConstructor, staticConstructorName, true, false);
|
||||
|
||||
for (Map.Entry<JavacNode, Boolean> field : gettersAndSetters.entrySet()) {
|
||||
new HandleGetter().generateGetterForField(field.getKey(), annotationNode.get(), AccessLevel.PUBLIC, true);
|
||||
if (field.getValue()) new HandleSetter().generateSetterForField(field.getKey(), annotationNode.get(), AccessLevel.PUBLIC, true);
|
||||
}
|
||||
|
||||
// TODO move this to the end OR move it to the top in eclipse.
|
||||
new HandleConstructor().generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, true);
|
||||
new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
|
||||
new HandleSetter().generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
|
||||
new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);
|
||||
new HandleToString().generateToStringForType(typeNode, annotationNode);
|
||||
|
||||
|
||||
@@ -56,6 +56,45 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
*/
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
public class HandleGetter implements JavacAnnotationHandler<Getter> {
|
||||
public boolean generateGetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelGetter) {
|
||||
if (checkForTypeLevelGetter) {
|
||||
if (typeNode != null) for (JavacNode child : typeNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (Javac.annotationTypeMatches(Getter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JCClassDecl typeDecl = null;
|
||||
if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
|
||||
long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
|
||||
boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
errorNode.addError("@Getter is only supported on a class or a field.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (JavacNode field : typeNode.down()) {
|
||||
if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, errorNode.get(), level);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean fieldQualifiesForGetterGeneration(JavacNode field) {
|
||||
if (field.getKind() != Kind.FIELD) return false;
|
||||
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.toString().startsWith("$")) return false;
|
||||
//Skip static fields.
|
||||
if ((fieldDecl.mods.flags & Flags.STATIC) != 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a getter on the stated field.
|
||||
*
|
||||
@@ -71,7 +110,7 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
|
||||
* @param fieldNode The node representing the field you want a getter for.
|
||||
* @param pos The node responsible for generating the getter (the {@code @Data} or {@code @Getter} annotation).
|
||||
*/
|
||||
public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean checkForTypeLevelGetter) {
|
||||
public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level) {
|
||||
for (JavacNode child : fieldNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (Javac.annotationTypeMatches(Getter.class, child)) {
|
||||
@@ -81,18 +120,6 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForTypeLevelGetter) {
|
||||
JavacNode containingType = fieldNode.up();
|
||||
if (containingType != null) for (JavacNode child : containingType.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (Javac.annotationTypeMatches(Getter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createGetterForField(level, fieldNode, fieldNode, false);
|
||||
}
|
||||
|
||||
@@ -109,21 +136,7 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
|
||||
return createGetterForFields(level, fields, annotationNode, true);
|
||||
}
|
||||
if (node.getKind() == Kind.TYPE) {
|
||||
JCClassDecl typeDecl = null;
|
||||
if (node.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) node.get();
|
||||
long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
|
||||
boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
annotationNode.addError("@Getter is only supported on a class.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (JavacNode field : node.down()) {
|
||||
if (field.getKind() != Kind.FIELD) continue;
|
||||
generateGetterForField(field, ast, level, false);
|
||||
}
|
||||
return true;
|
||||
return generateGetterForType(node, annotationNode, level, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -139,7 +152,7 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
|
||||
private boolean createGetterForField(AccessLevel level,
|
||||
JavacNode fieldNode, JavacNode errorNode, boolean whineIfExists) {
|
||||
if (fieldNode.getKind() != Kind.FIELD) {
|
||||
errorNode.addError("@Getter is only supported on a field.");
|
||||
errorNode.addError("@Getter is only supported on a class or a field.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ import javax.lang.model.type.TypeVisitor;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Setter;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.handlers.TransformationsUtil;
|
||||
import lombok.javac.Javac;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
@@ -44,7 +44,6 @@ import org.mangosdk.spi.ProviderFor;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.TypeTags;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAssign;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
@@ -55,15 +54,53 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCStatement;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
|
||||
/**
|
||||
* Handles the {@code lombok.Setter} annotation for javac.
|
||||
*/
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
public class HandleSetter implements JavacAnnotationHandler<Setter> {
|
||||
public boolean generateSetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelSetter) {
|
||||
if (checkForTypeLevelSetter) {
|
||||
if (typeNode != null) for (JavacNode child : typeNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (Javac.annotationTypeMatches(Setter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JCClassDecl typeDecl = null;
|
||||
if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
|
||||
long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
|
||||
boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
errorNode.addError("@Setter is only supported on a class or a field.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (JavacNode field : typeNode.down()) {
|
||||
if (field.getKind() != Kind.FIELD) continue;
|
||||
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
|
||||
//Skip fields that start with $
|
||||
if (fieldDecl.name.toString().startsWith("$")) continue;
|
||||
//Skip static fields.
|
||||
if ((fieldDecl.mods.flags & Flags.STATIC) != 0) continue;
|
||||
//Skip final fields.
|
||||
if ((fieldDecl.mods.flags & Flags.FINAL) != 0) continue;
|
||||
|
||||
generateSetterForField(field, errorNode.get(), level);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a setter on the stated field.
|
||||
*
|
||||
@@ -79,7 +116,7 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> {
|
||||
* @param fieldNode The node representing the field you want a setter for.
|
||||
* @param pos The node responsible for generating the setter (the {@code @Data} or {@code @Setter} annotation).
|
||||
*/
|
||||
public void generateSetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean checkForTypeLevelSetter) {
|
||||
public void generateSetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level) {
|
||||
for (JavacNode child : fieldNode.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (Javac.annotationTypeMatches(Setter.class, child)) {
|
||||
@@ -89,18 +126,6 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> {
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForTypeLevelSetter) {
|
||||
JavacNode containingType = fieldNode.up();
|
||||
if (containingType != null) for (JavacNode child : containingType.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
if (Javac.annotationTypeMatches(Setter.class, child)) {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createSetterForField(level, fieldNode, fieldNode, false);
|
||||
}
|
||||
|
||||
@@ -118,21 +143,7 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> {
|
||||
return createSetterForFields(level, fields, annotationNode, true);
|
||||
}
|
||||
if (node.getKind() == Kind.TYPE) {
|
||||
JCClassDecl typeDecl = null;
|
||||
if (node.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) node.get();
|
||||
long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
|
||||
boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
annotationNode.addError("@Setter is only supported on a class.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (JavacNode field : node.down()) {
|
||||
if (field.getKind() != Kind.FIELD) continue;
|
||||
generateSetterForField(field, ast, level, false);
|
||||
}
|
||||
return true;
|
||||
return generateSetterForType(node, annotationNode, level, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -148,7 +159,7 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> {
|
||||
private boolean createSetterForField(AccessLevel level,
|
||||
JavacNode fieldNode, JavacNode errorNode, boolean whineIfExists) {
|
||||
if (fieldNode.getKind() != Kind.FIELD) {
|
||||
fieldNode.addError("@Setter is only supported on a field.");
|
||||
fieldNode.addError("@Setter is only supported on a class or a field.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,12 +21,18 @@
|
||||
*/
|
||||
package lombok.javac.handlers;
|
||||
|
||||
import static lombok.javac.Javac.annotationTypeMatches;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.handlers.TransformationsUtil;
|
||||
import lombok.javac.Javac;
|
||||
import lombok.javac.JavacNode;
|
||||
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
@@ -270,7 +276,17 @@ public class JavacHandlerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static JCMethodDecl findGetter(JavacNode field) {
|
||||
private static class GetterMethod {
|
||||
private final Name name;
|
||||
private final JCExpression type;
|
||||
|
||||
GetterMethod(Name name, JCExpression type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private static GetterMethod findGetter(JavacNode field) {
|
||||
JCVariableDecl decl = (JCVariableDecl)field.get();
|
||||
JavacNode typeNode = field.up();
|
||||
for (String potentialGetterName : toAllGetterNames(decl)) {
|
||||
@@ -280,15 +296,49 @@ public class JavacHandlerUtil {
|
||||
for (JavacNode potentialGetter : typeNode.down()) {
|
||||
if (potentialGetter.getKind() != Kind.METHOD) continue;
|
||||
JCMethodDecl method = (JCMethodDecl) potentialGetter.get();
|
||||
if (!method.name.contentEquals(potentialGetterName)) continue;
|
||||
/** static getX() methods don't count. */
|
||||
if ((method.mods.flags & Flags.STATIC) != 0) continue;
|
||||
/** Nor do getters with a non-empty parameter list. */
|
||||
if (method.params != null && method.params.size() > 0) continue;
|
||||
return method;
|
||||
return new GetterMethod(method.name, method.restype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the field has a @Getter annotation.
|
||||
|
||||
boolean hasGetterAnnotation = false;
|
||||
|
||||
for (JavacNode child : field.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
|
||||
AnnotationValues<Getter> ann = Javac.createAnnotation(Getter.class, child);
|
||||
if (ann.getInstance().value() == AccessLevel.NONE) return null; //Definitely WONT have a getter.
|
||||
hasGetterAnnotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the class has a @Getter annotation.
|
||||
|
||||
if (!hasGetterAnnotation && new HandleGetter().fieldQualifiesForGetterGeneration(field)) {
|
||||
//Check if the class has @Getter or @Data annotation.
|
||||
|
||||
JavacNode containingType = field.up();
|
||||
if (containingType != null) for (JavacNode child : containingType.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Data.class, child)) hasGetterAnnotation = true;
|
||||
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
|
||||
AnnotationValues<Getter> ann = Javac.createAnnotation(Getter.class, child);
|
||||
if (ann.getInstance().value() == AccessLevel.NONE) return null; //Definitely WONT have a getter.
|
||||
hasGetterAnnotation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasGetterAnnotation) {
|
||||
String getterName = toGetterName(decl);
|
||||
return new GetterMethod(field.toName(getterName), decl.vartype);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -298,13 +348,13 @@ public class JavacHandlerUtil {
|
||||
* @see #createFieldAccessor(TreeMaker, JavacNode)
|
||||
*/
|
||||
static JCExpression getFieldType(JavacNode field, boolean useFieldsDirectly) {
|
||||
JCMethodDecl getter = useFieldsDirectly ? null : findGetter(field);
|
||||
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
|
||||
|
||||
if (getter == null) {
|
||||
return ((JCVariableDecl)field.get()).vartype;
|
||||
}
|
||||
|
||||
return getter.restype;
|
||||
return getter.type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,7 +365,7 @@ public class JavacHandlerUtil {
|
||||
}
|
||||
|
||||
static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, boolean useFieldsDirectly, JCExpression receiver) {
|
||||
JCMethodDecl getter = useFieldsDirectly ? null : findGetter(field);
|
||||
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
|
||||
|
||||
if (getter == null) {
|
||||
return maker.Select(receiver, ((JCVariableDecl)field.get()).name);
|
||||
|
||||
@@ -40,7 +40,7 @@ class DataWithGetter {
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "DataWithGetterNone(x=" + this.getX() + ", y=" + this.getY() + ", z=" + this.getZ() + ")";
|
||||
return "DataWithGetter(x=" + this.getX() + ", y=" + this.getY() + ", z=" + this.getZ() + ")";
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public int getX() {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
return result;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((((("DataWithGetterNone(x=" + this.getX()) + ", y=") + this.getY()) + ", z=") + this.getZ()) + ")");
|
||||
return (((((("DataWithGetter(x=" + this.getX()) + ", y=") + this.getY()) + ", z=") + this.getZ()) + ")");
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") int getX() {
|
||||
return this.x;
|
||||
|
||||
Reference in new issue
Block a user