diff options
25 files changed, 252 insertions, 94 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index b49f6de8..058a478a 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,6 +2,7 @@ Lombok Changelog ---------------- ### v1.12.7 "Edgy Guinea Pig" +* FEATURE: You can now configure aspects of lombok project wide (or even workspace wide, or just for a single package) via the [configuration system](http://projectlombok.org/features/configuration.html). You can configure many things; run `java -jar lombok.jar config -gv` for the complete list. * DEPRECATION: `@Delegate` has been moved to `lombok.experimental.Delegate`, and corner cases such as recursive delegation (delegating a type that itself has fields or methods annotated with `@Delegate`) are now error conditions. See the [feature documentation](http://projectlombok.org/features/experimental/Delegate.html) for more information. * FEATURE: It is now possible to put annotations, such as `@Nullable`, on the one parameter of generated `equals()` methods by specifying the `onParam=` option on `@EqualsAndHashCode`, similar to how that feature already exists for `@Setter`. [Issue #674](https://code.google.com/p/projectlombok/issues/detail?id=674) * CHANGE: suppressConstructorProperties should now be configured via lombok configuration. [Issue #659](https://code.google.com/p/projectlombok/issues/detail?id=659) diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 608bedd1..a93af395 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -181,6 +181,13 @@ public class ConfigurationKeys { // ----- NonNull ----- /** + * lombok configuration: {@code lombok.nonNull.exceptionType} = <String: <em>a java exception type, such as {@code java.lang.IllegalArgumentException}</em>> (default: {@code java.lang.NullPointerException}). + * + * Sets the exception to throw if {@code @NonNull} is applied to a method parameter, and a caller passes in {@code null}. + */ + public static final ConfigurationKey<String> NON_NULL_EXCEPTION_TYPE = new ConfigurationKey<String>("lombok.nonNull.exceptionType", "The type of the exception to throw if a passed-in argument is null.") {}; + + /** * lombok configuration: {@code lombok.nonNull.flagUsage} = {@code WARNING} | {@code ERROR}. * * <em>Implementation note: This field is supposed to be lombok.NonNull itself, but jdk6 and 7 have bugs where fields in annotations don't work well.</em> @@ -269,7 +276,7 @@ public class ConfigurationKeys { public static final ConfigurationKey<FlagUsageType> LOG_XSLF4J_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.xslf4j.flagUsage", "Emit a warning or error if @XSlf4j is used.") {}; /** - * lombok configuration: {@code lombok.log.fieldName} = "aJavaIdentifier". + * lombok configuration: {@code lombok.log.fieldName} = <String: aJavaIdentifier> (Default: {@code log}). * * If set the various log annotations (which make a log field) will use the stated identifier instead of {@code log} as a name. */ diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index fe2f3406..cbfd3f8c 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -68,6 +68,30 @@ public class HandlerUtil { return 97; } + /** Checks if the input is a valid class reference (not a primitive and does not have generics). */ + public static boolean isLegalBasicClassReference(String in) { + boolean atStartOfIdentifier = true; + + for (int i = 0; i < in.length(); i++) { + char c = in.charAt(i); + + if (atStartOfIdentifier) { + if (!Character.isJavaIdentifierStart(c)) return false; + atStartOfIdentifier = false; + continue; + } + + if (c == '.') { + atStartOfIdentifier = true; + continue; + } + + if (!Character.isJavaIdentifierPart(c)) return false; + } + + return !atStartOfIdentifier; + } + /** Checks if the given name is a valid identifier. * * If it is, this returns {@code true} and does nothing else. @@ -204,6 +228,8 @@ public class HandlerUtil { /** Matches the simple part of any annotation that lombok considers as indicative of Nullable status. */ public static final Pattern NULLABLE_PATTERN = Pattern.compile("^(?:nullable|checkfornull)$", Pattern.CASE_INSENSITIVE); + public static final String DEFAULT_EXCEPTION_FOR_NON_NULL = "java.lang.NullPointerException"; + /** * Generates a getter name from a given field name. * diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index a93f321b..022cad91 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1396,17 +1396,35 @@ public class EclipseHandlerUtil { } /** - * Generates a new statement that checks if the given variable is null, and if so, throws a {@code NullPointerException} with the + * Generates a new statement that checks if the given variable is null, and if so, throws a specified exception with the * variable name as message. + * + * @param exName The name of the exception to throw; normally {@code java.lang.NullPointerException}. */ - public static Statement generateNullCheck(AbstractVariableDeclaration variable, ASTNode source) { + public static Statement generateNullCheck(AbstractVariableDeclaration variable, EclipseNode sourceNode) { + String exceptionType = sourceNode.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE); + if (exceptionType == null) { + exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; + } else { + if (!HandlerUtil.isLegalBasicClassReference(exceptionType)) { + sourceNode.addWarning("Configuration key contains invalid java type reference '" + exceptionType + "'; use something like 'java.lang.NullPointerException' as value for this key."); + exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; + } + } + + ASTNode source = sourceNode.get(); + int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; if (isPrimitive(variable.type)) return null; AllocationExpression exception = new AllocationExpression(); setGeneratedBy(exception, source); - exception.type = new QualifiedTypeReference(fromQualifiedName("java.lang.NullPointerException"), new long[]{p, p, p}); + int partCount = 0; + for (int i = 0; i < exceptionType.length(); i++) if (exceptionType.charAt(i) == '.') partCount++; + long[] ps = new long[partCount]; + Arrays.fill(ps, 0L); + exception.type = new QualifiedTypeReference(fromQualifiedName(exceptionType), ps); setGeneratedBy(exception.type, source); exception.arguments = new Expression[] { new StringLiteral(variable.name, pS, pE, 0)}; setGeneratedBy(exception.arguments[0], source); diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 64e01c6e..522501f6 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -120,7 +120,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { fields.add(fieldNode); } - new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, fields, null, SkipIfConstructorExists.I_AM_BUILDER, null, Collections.<Annotation>emptyList(), ast); + new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, fields, null, SkipIfConstructorExists.I_AM_BUILDER, null, + Collections.<Annotation>emptyList(), annotationNode); returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p); typeParams = td.typeParameters; @@ -204,12 +205,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { List<EclipseNode> fieldNodes = addFieldsToBuilder(builderType, namesOfParameters, typesOfParameters, ast); List<AbstractMethodDeclaration> newMethods = new ArrayList<AbstractMethodDeclaration>(); for (EclipseNode fieldNode : fieldNodes) { - MethodDeclaration newMethod = makeSetterMethodForBuilder(builderType, fieldNode, ast, builderInstance.fluent(), builderInstance.chain()); + MethodDeclaration newMethod = makeSetterMethodForBuilder(builderType, fieldNode, annotationNode, builderInstance.fluent(), builderInstance.chain()); if (newMethod != null) newMethods.add(newMethod); } if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) { - ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), null, ast, Collections.<Annotation>emptyList()); + ConstructorDeclaration cd = HandleConstructor.createConstructor( + AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), null, + annotationNode, Collections.<Annotation>emptyList()); if (cd != null) injectMethod(builderType, cd); } @@ -334,7 +337,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { private static final AbstractMethodDeclaration[] EMPTY = {}; - public MethodDeclaration makeSetterMethodForBuilder(EclipseNode builderType, EclipseNode fieldNode, ASTNode source, boolean fluent, boolean chain) { + public MethodDeclaration makeSetterMethodForBuilder(EclipseNode builderType, EclipseNode fieldNode, EclipseNode sourceNode, boolean fluent, boolean chain) { TypeDeclaration td = (TypeDeclaration) builderType.get(); AbstractMethodDeclaration[] existing = td.methods; if (existing == null) existing = EMPTY; @@ -352,7 +355,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { String setterName = fluent ? fieldNode.getName() : toSetterName(builderType.getAst(), null, fieldNode.getName(), isBoolean); return HandleSetter.createSetter(td, fieldNode, setterName, chain, ClassFileConstants.AccPublic, - source, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList()); + sourceNode, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList()); } public EclipseNode findInnerClass(EclipseNode parent, String name) { diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 4e35ebb6..b72d000f 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -82,7 +82,7 @@ public class HandleConstructor { List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor=", annotationNode); - new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, SkipIfConstructorExists.NO, null, onConstructor, ast); + new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, SkipIfConstructorExists.NO, null, onConstructor, annotationNode); } } @@ -106,7 +106,9 @@ public class HandleConstructor { List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor=", annotationNode); - new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, onConstructor, ast); + new HandleConstructor().generateConstructor( + typeNode, level, findRequiredFields(typeNode), staticName, SkipIfConstructorExists.NO, + suppressConstructorProperties, onConstructor, annotationNode); } } @@ -158,7 +160,9 @@ public class HandleConstructor { List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor=", annotationNode); - new HandleConstructor().generateConstructor(typeNode, level, findAllFields(typeNode), staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, onConstructor, ast); + new HandleConstructor().generateConstructor( + typeNode, level, findAllFields(typeNode), staticName, SkipIfConstructorExists.NO, + suppressConstructorProperties, onConstructor, annotationNode); } } @@ -176,19 +180,29 @@ public class HandleConstructor { return true; } - public void generateRequiredArgsConstructor(EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, List<Annotation> onConstructor, ASTNode source) { - generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, null, onConstructor, source); + public void generateRequiredArgsConstructor( + EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, + List<Annotation> onConstructor, EclipseNode sourceNode) { + + generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, null, onConstructor, sourceNode); } - public void generateAllArgsConstructor(EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, List<Annotation> onConstructor, ASTNode source) { - generateConstructor(typeNode, level, findAllFields(typeNode), staticName, skipIfConstructorExists, null, onConstructor, source); + public void generateAllArgsConstructor( + EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, + List<Annotation> onConstructor, EclipseNode sourceNode) { + + generateConstructor(typeNode, level, findAllFields(typeNode), staticName, skipIfConstructorExists, null, onConstructor, sourceNode); } public enum SkipIfConstructorExists { YES, NO, I_AM_BUILDER; } - public void generateConstructor(EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, String staticName, SkipIfConstructorExists skipIfConstructorExists, Boolean suppressConstructorProperties, List<Annotation> onConstructor, ASTNode source) { + public void generateConstructor( + EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, String staticName, SkipIfConstructorExists skipIfConstructorExists, + Boolean suppressConstructorProperties, List<Annotation> onConstructor, EclipseNode sourceNode) { + + ASTNode source = sourceNode.get(); boolean staticConstrRequired = staticName != null && !staticName.equals(""); if (skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; @@ -209,7 +223,9 @@ public class HandleConstructor { // will take care of it. However, @Data also wants a specific static name; this will be ignored; the appropriate way to do this is to use // the 'staticName' parameter of the @XArgsConstructor you've stuck on your type. // We should warn that we're ignoring @Data's 'staticConstructor' param. - typeNode.addWarning("Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.", source.sourceStart, source.sourceEnd); + typeNode.addWarning( + "Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.", + source.sourceStart, source.sourceEnd); } return; } @@ -217,7 +233,9 @@ public class HandleConstructor { } } - ConstructorDeclaration constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source, onConstructor); + ConstructorDeclaration constr = createConstructor( + staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, + suppressConstructorProperties, sourceNode, onConstructor); injectMethod(typeNode, constr); if (staticConstrRequired) { MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, fields, source); @@ -259,8 +277,9 @@ public class HandleConstructor { public static ConstructorDeclaration createConstructor( AccessLevel level, EclipseNode type, Collection<EclipseNode> fields, - Boolean suppressConstructorProperties, ASTNode source, List<Annotation> onConstructor) { + Boolean suppressConstructorProperties, EclipseNode sourceNode, List<Annotation> onConstructor) { + ASTNode source = sourceNode.get(); TypeDeclaration typeDeclaration = ((TypeDeclaration)type.get()); long p = (long)source.sourceStart << 32 | source.sourceEnd; @@ -311,7 +330,7 @@ public class HandleConstructor { Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN); Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN); if (nonNulls.length != 0) { - Statement nullCheck = generateNullCheck(field, source); + Statement nullCheck = generateNullCheck(field, sourceNode); if (nullCheck != null) nullChecks.add(nullCheck); } Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables); diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java index a6a8842d..0ff65a47 100644 --- a/src/core/lombok/eclipse/handlers/HandleData.java +++ b/src/core/lombok/eclipse/handlers/HandleData.java @@ -70,6 +70,8 @@ public class HandleData extends EclipseAnnotationHandler<Data> { 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(), SkipIfConstructorExists.YES, Collections.<Annotation>emptyList(), ast); + new HandleConstructor().generateRequiredArgsConstructor( + typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES, + Collections.<Annotation>emptyList(), annotationNode); } } diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java index 79bb7a08..d904de2f 100644 --- a/src/core/lombok/eclipse/handlers/HandleNonNull.java +++ b/src/core/lombok/eclipse/handlers/HandleNonNull.java @@ -99,7 +99,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and // wrap all references to it in the super/this to a call to this method. - Statement nullCheck = generateNullCheck(arg, ast); + Statement nullCheck = generateNullCheck(arg, annotationNode); if (nullCheck == null) { // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning. diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 74ef07b5..c22af676 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -90,7 +90,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { //Skip final fields. if ((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0) continue; - generateSetterForField(field, pos.get(), level); + generateSetterForField(field, pos, level); } return true; } @@ -107,7 +107,7 @@ public class HandleSetter extends 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) { + public void generateSetterForField(EclipseNode fieldNode, EclipseNode sourceNode, AccessLevel level) { if (hasAnnotation(Setter.class, fieldNode)) { //The annotation will make it happen, so we can skip it. return; @@ -115,7 +115,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { List<Annotation> empty = Collections.emptyList(); - createSetterForField(level, fieldNode, fieldNode, pos, false, empty, empty); + createSetterForField(level, fieldNode, sourceNode, false, empty, empty); } public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) { @@ -130,7 +130,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { switch (node.getKind()) { case FIELD: - createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, onParam); + createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod, onParam); break; case TYPE: if (!onMethod.isEmpty()) { @@ -144,19 +144,20 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { } } - public void createSetterForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { + public void createSetterForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode sourceNode, boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { for (EclipseNode fieldNode : fieldNodes) { - createSetterForField(level, fieldNode, errorNode, source, whineIfExists, onMethod, onParam); + createSetterForField(level, fieldNode, sourceNode, whineIfExists, onMethod, onParam); } } public void createSetterForField( - AccessLevel level, EclipseNode fieldNode, EclipseNode errorNode, - ASTNode source, boolean whineIfExists, List<Annotation> onMethod, + AccessLevel level, EclipseNode fieldNode, EclipseNode sourceNode, + boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { + ASTNode source = sourceNode.get(); if (fieldNode.getKind() != Kind.FIELD) { - errorNode.addError("@Setter is only supported on a class or a field."); + sourceNode.addError("@Setter is only supported on a class or a field."); return; } @@ -167,7 +168,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { boolean shouldReturnThis = shouldReturnThis(fieldNode); if (setterName == null) { - errorNode.addWarning("Not generating setter for this field: It does not fit your @Accessors prefix list."); + fieldNode.addWarning("Not generating setter for this field: It does not fit your @Accessors prefix list."); return; } @@ -181,7 +182,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (whineIfExists) { String altNameExpl = ""; if (!altName.equals(setterName)) altNameExpl = String.format(" (%s)", altName); - errorNode.addWarning( + fieldNode.addWarning( String.format("Not generating %s(): A method with that name already exists%s", setterName, altNameExpl)); } return; @@ -191,12 +192,13 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { } } - MethodDeclaration method = createSetter((TypeDeclaration) fieldNode.up().get(), fieldNode, setterName, shouldReturnThis, modifier, source, onMethod, onParam); + MethodDeclaration method = createSetter((TypeDeclaration) fieldNode.up().get(), fieldNode, setterName, shouldReturnThis, modifier, sourceNode, onMethod, onParam); injectMethod(fieldNode.up(), method); } - static MethodDeclaration createSetter(TypeDeclaration parent, EclipseNode fieldNode, String name, boolean shouldReturnThis, int modifier, ASTNode source, List<Annotation> onMethod, List<Annotation> onParam) { + static MethodDeclaration createSetter(TypeDeclaration parent, EclipseNode fieldNode, String name, boolean shouldReturnThis, int modifier, EclipseNode sourceNode, List<Annotation> onMethod, List<Annotation> onParam) { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); + ASTNode source = sourceNode.get(); int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; MethodDeclaration method = new MethodDeclaration(parent.compilationResult); @@ -239,7 +241,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (nonNulls.length == 0) { statements.add(assignment); } else { - Statement nullCheck = generateNullCheck(field, source); + Statement nullCheck = generateNullCheck(field, sourceNode); if (nullCheck != null) statements.add(nullCheck); statements.add(assignment); } diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java index 211b337a..79c11771 100644 --- a/src/core/lombok/eclipse/handlers/HandleValue.java +++ b/src/core/lombok/eclipse/handlers/HandleValue.java @@ -83,6 +83,7 @@ public class HandleValue extends EclipseAnnotationHandler<Value> { new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode); new HandleToString().generateToStringForType(typeNode, annotationNode); - new HandleConstructor().generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES, Collections.<Annotation>emptyList(), ast); + new HandleConstructor().generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES, + Collections.<Annotation>emptyList(), annotationNode); } } diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java index 30306b72..8b038676 100644 --- a/src/core/lombok/eclipse/handlers/HandleWither.java +++ b/src/core/lombok/eclipse/handlers/HandleWither.java @@ -88,7 +88,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { //Skip final fields. if ((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0 && fieldDecl.initialization != null) continue; - generateWitherForField(field, pos.get(), level); + generateWitherForField(field, pos, level); } return true; } @@ -106,7 +106,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { * If not, the wither 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 generateWitherForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level) { + public void generateWitherForField(EclipseNode fieldNode, EclipseNode sourceNode, AccessLevel level) { for (EclipseNode child : fieldNode.down()) { if (child.getKind() == Kind.ANNOTATION) { if (annotationTypeMatches(Wither.class, child)) { @@ -117,7 +117,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { } List<Annotation> empty = Collections.emptyList(); - createWitherForField(level, fieldNode, fieldNode, pos, false, empty, empty); + createWitherForField(level, fieldNode, sourceNode, false, empty, empty); } @Override public void handle(AnnotationValues<Wither> annotation, Annotation ast, EclipseNode annotationNode) { @@ -132,7 +132,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { switch (node.getKind()) { case FIELD: - createWitherForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, onParam); + createWitherForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod, onParam); break; case TYPE: if (!onMethod.isEmpty()) { @@ -146,18 +146,20 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { } } - public void createWitherForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { + public void createWitherForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode sourceNode, boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { for (EclipseNode fieldNode : fieldNodes) { - createWitherForField(level, fieldNode, errorNode, source, whineIfExists, onMethod, onParam); + createWitherForField(level, fieldNode, sourceNode, whineIfExists, onMethod, onParam); } } public void createWitherForField( - AccessLevel level, EclipseNode fieldNode, EclipseNode errorNode, - ASTNode source, boolean whineIfExists, List<Annotation> onMethod, + AccessLevel level, EclipseNode fieldNode, EclipseNode sourceNode, + boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { + + ASTNode source = sourceNode.get(); if (fieldNode.getKind() != Kind.FIELD) { - errorNode.addError("@Wither is only supported on a class or a field."); + sourceNode.addError("@Wither is only supported on a class or a field."); return; } @@ -167,22 +169,22 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { String witherName = toWitherName(fieldNode, isBoolean); if (witherName == null) { - errorNode.addWarning("Not generating wither for this field: It does not fit your @Accessors prefix list."); + fieldNode.addWarning("Not generating wither for this field: It does not fit your @Accessors prefix list."); return; } if ((field.modifiers & ClassFileConstants.AccStatic) != 0) { - errorNode.addWarning("Not generating wither for this field: Withers cannot be generated for static fields."); + fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for static fields."); return; } if ((field.modifiers & ClassFileConstants.AccFinal) != 0 && field.initialization != null) { - errorNode.addWarning("Not generating wither for this field: Withers cannot be generated for final, initialized fields."); + fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for final, initialized fields."); return; } if (field.name != null && field.name.length > 0 && field.name[0] == '$') { - errorNode.addWarning("Not generating wither for this field: Withers cannot be generated for fields starting with $."); + fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for fields starting with $."); return; } @@ -194,7 +196,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { if (whineIfExists) { String altNameExpl = ""; if (!altName.equals(witherName)) altNameExpl = String.format(" (%s)", altName); - errorNode.addWarning( + fieldNode.addWarning( String.format("Not generating %s(): A method with that name already exists%s", witherName, altNameExpl)); } return; @@ -206,11 +208,12 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { int modifier = toEclipseModifier(level); - MethodDeclaration method = createWither((TypeDeclaration) fieldNode.up().get(), fieldNode, witherName, modifier, source, onMethod, onParam); + MethodDeclaration method = createWither((TypeDeclaration) fieldNode.up().get(), fieldNode, witherName, modifier, sourceNode, onMethod, onParam); injectMethod(fieldNode.up(), method); } - public MethodDeclaration createWither(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, List<Annotation> onMethod, List<Annotation> onParam) { + public MethodDeclaration createWither(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, EclipseNode sourceNode, List<Annotation> onMethod, List<Annotation> onParam) { + ASTNode source = sourceNode.get(); if (name == null) return null; FieldDeclaration field = (FieldDeclaration) fieldNode.get(); int pS = source.sourceStart, pE = source.sourceEnd; @@ -273,7 +276,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN); List<Statement> statements = new ArrayList<Statement>(5); if (nonNulls.length > 0) { - Statement nullCheck = generateNullCheck(field, source); + Statement nullCheck = generateNullCheck(field, sourceNode); if (nullCheck != null) statements.add(nullCheck); } statements.add(returnStatement); diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index bf3b39dc..1885b8b4 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -194,12 +194,12 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { java.util.List<JavacNode> fieldNodes = addFieldsToBuilder(builderType, namesOfParameters, typesOfParameters, ast); java.util.List<JCMethodDecl> newMethods = new ArrayList<JCMethodDecl>(); for (JavacNode fieldNode : fieldNodes) { - JCMethodDecl newMethod = makeSetterMethodForBuilder(builderType, fieldNode, ast, builderInstance.fluent(), builderInstance.chain()); + JCMethodDecl newMethod = makeSetterMethodForBuilder(builderType, fieldNode, annotationNode, builderInstance.fluent(), builderInstance.chain()); if (newMethod != null) newMethods.add(newMethod); } if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), null, ast); + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), null, annotationNode); if (cd != null) injectMethod(builderType, cd); } @@ -300,7 +300,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } - public JCMethodDecl makeSetterMethodForBuilder(JavacNode builderType, JavacNode fieldNode, JCTree source, boolean fluent, boolean chain) { + public JCMethodDecl makeSetterMethodForBuilder(JavacNode builderType, JavacNode fieldNode, JavacNode source, boolean fluent, boolean chain) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 0618706e..6043d1cb 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -214,7 +214,7 @@ public class HandleConstructor { } } - JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, suppressConstructorProperties, source.get()); + JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, suppressConstructorProperties, source); injectMethod(typeNode, constr); if (staticConstrRequired) { JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, fields, source.get()); @@ -236,7 +236,7 @@ public class HandleConstructor { mods.annotations = mods.annotations.append(annotation); } - public static JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, Boolean suppressConstructorProperties, JCTree source) { + public static JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, Boolean suppressConstructorProperties, JavacNode source) { JavacTreeMaker maker = typeNode.getTreeMaker(); boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0; @@ -268,7 +268,7 @@ public class HandleConstructor { assigns.append(maker.Exec(assign)); if (!nonNulls.isEmpty()) { - JCStatement nullCheck = generateNullCheck(maker, fieldNode); + JCStatement nullCheck = generateNullCheck(maker, fieldNode, source); if (nullCheck != null) nullChecks.append(nullCheck); } } @@ -280,7 +280,8 @@ public class HandleConstructor { if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor)); return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"), - null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source, typeNode.getContext()); + null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), + maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source.get(), typeNode.getContext()); } public static boolean isLocalType(JavacNode type) { diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java index 172e70b3..cd8e3402 100644 --- a/src/core/lombok/javac/handlers/HandleNonNull.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.java @@ -84,8 +84,6 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { return; } -// if (JavacHandlerUtil.isGenerated(declaration)) return; - if (declaration.body == null) { annotationNode.addWarning("@NonNull is meaningless on a parameter of an abstract method."); return; @@ -95,7 +93,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and // wrap all references to it in the super/this to a call to this method. - JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), annotationNode.up()), ast, annotationNode.getContext()); + JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), annotationNode.up(), annotationNode), ast, annotationNode.getContext()); if (nullCheck == null) { // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning. diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index fbc9ef46..3c4329b2 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -41,7 +41,6 @@ import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCAssign; import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -52,7 +51,6 @@ import com.sun.tools.javac.tree.JCTree.JCReturn; 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.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -90,7 +88,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { //Skip final fields. if ((fieldDecl.mods.flags & Flags.FINAL) != 0) continue; - generateSetterForField(field, errorNode.get(), level); + generateSetterForField(field, errorNode, level); } } @@ -109,13 +107,13 @@ public class HandleSetter extends 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) { + public void generateSetterForField(JavacNode fieldNode, JavacNode sourceNode, AccessLevel level) { if (hasAnnotation(Setter.class, fieldNode)) { //The annotation will make it happen, so we can skip it. return; } - createSetterForField(level, fieldNode, fieldNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); + createSetterForField(level, fieldNode, sourceNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); } @Override public void handle(AnnotationValues<Setter> annotation, JCAnnotation ast, JavacNode annotationNode) { @@ -150,7 +148,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { } } - public void createSetterForField(AccessLevel level, JavacNode fieldNode, JavacNode source, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + public void createSetterForField(AccessLevel level, JavacNode fieldNode, JavacNode sourceNode, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { if (fieldNode.getKind() != Kind.FIELD) { fieldNode.addError("@Setter is only supported on a class or a field."); return; @@ -160,12 +158,12 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { String methodName = toSetterName(fieldNode); if (methodName == null) { - source.addWarning("Not generating setter for this field: It does not fit your @Accessors prefix list."); + fieldNode.addWarning("Not generating setter for this field: It does not fit your @Accessors prefix list."); return; } if ((fieldDecl.mods.flags & Flags.FINAL) != 0) { - source.addWarning("Not generating setter for this field: Setters cannot be generated for final fields."); + fieldNode.addWarning("Not generating setter for this field: Setters cannot be generated for final fields."); return; } @@ -177,7 +175,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { if (whineIfExists) { String altNameExpl = ""; if (!altName.equals(methodName)) altNameExpl = String.format(" (%s)", altName); - source.addWarning( + fieldNode.addWarning( String.format("Not generating %s(): A method with that name already exists%s", methodName, altNameExpl)); } return; @@ -189,17 +187,17 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC); - JCMethodDecl createdSetter = createSetter(access, fieldNode, fieldNode.getTreeMaker(), source.get(), onMethod, onParam); + JCMethodDecl createdSetter = createSetter(access, fieldNode, fieldNode.getTreeMaker(), sourceNode, onMethod, onParam); injectMethod(fieldNode.up(), createdSetter); } - public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { String setterName = toSetterName(field); boolean returnThis = shouldReturnThis(field); return createSetter(access, field, treeMaker, setterName, returnThis, source, onMethod, onParam); } - public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, String setterName, boolean shouldReturnThis, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, String setterName, boolean shouldReturnThis, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { if (setterName == null) return null; JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); @@ -220,7 +218,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { if (nonNulls.isEmpty()) { statements.append(treeMaker.Exec(assign)); } else { - JCStatement nullCheck = generateNullCheck(treeMaker, field); + JCStatement nullCheck = generateNullCheck(treeMaker, field, source); if (nullCheck != null) statements.append(nullCheck); statements.append(treeMaker.Exec(assign)); } @@ -253,7 +251,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { } JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, - methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source, field.getContext()); + methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source.get(), field.getContext()); copyJavadoc(field, decl, CopyJavadoc.SETTER); return decl; } diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java index 7b55b671..8a7b49b2 100644 --- a/src/core/lombok/javac/handlers/HandleWither.java +++ b/src/core/lombok/javac/handlers/HandleWither.java @@ -41,7 +41,6 @@ import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCClassDecl; @@ -161,22 +160,22 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { String methodName = toWitherName(fieldNode); if (methodName == null) { - source.addWarning("Not generating wither for this field: It does not fit your @Accessors prefix list."); + fieldNode.addWarning("Not generating wither for this field: It does not fit your @Accessors prefix list."); return; } if ((fieldDecl.mods.flags & Flags.STATIC) != 0) { - source.addWarning("Not generating wither for this field: Withers cannot be generated for static fields."); + fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for static fields."); return; } if ((fieldDecl.mods.flags & Flags.FINAL) != 0 && fieldDecl.init != null) { - source.addWarning("Not generating wither for this field: Withers cannot be generated for final, initialized fields."); + fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for final, initialized fields."); return; } if (fieldDecl.name.toString().startsWith("$")) { - source.addWarning("Not generating wither for this field: Withers cannot be generated for fields starting with $."); + fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for fields starting with $."); return; } @@ -188,7 +187,7 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { if (whineIfExists) { String altNameExpl = ""; if (!altName.equals(methodName)) altNameExpl = String.format(" (%s)", altName); - source.addWarning( + fieldNode.addWarning( String.format("Not generating %s(): A method with that name already exists%s", methodName, altNameExpl)); } return; @@ -200,11 +199,11 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { long access = toJavacModifier(level); - JCMethodDecl createdWither = createWither(access, fieldNode, fieldNode.getTreeMaker(), source.get(), onMethod, onParam); + JCMethodDecl createdWither = createWither(access, fieldNode, fieldNode.getTreeMaker(), source, onMethod, onParam); injectMethod(fieldNode.up(), createdWither); } - public JCMethodDecl createWither(long access, JavacNode field, JavacTreeMaker maker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + public JCMethodDecl createWither(long access, JavacNode field, JavacTreeMaker maker, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { String witherName = toWitherName(field); if (witherName == null) return null; @@ -249,7 +248,7 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { if (nonNulls.isEmpty()) { statements.append(returnStatement); } else { - JCStatement nullCheck = generateNullCheck(maker, field); + JCStatement nullCheck = generateNullCheck(maker, field, source); if (nullCheck != null) statements.append(nullCheck); statements.append(returnStatement); } @@ -268,7 +267,7 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { annsOnMethod = annsOnMethod.prepend(maker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil())); } JCMethodDecl decl = recursiveSetGeneratedBy(maker.MethodDef(maker.Modifiers(access, annsOnMethod), methodName, returnType, - methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source, field.getContext()); + methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source.get(), field.getContext()); copyJavadoc(field, decl, CopyJavadoc.WITHER); return decl; } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index aa395e08..524af5de 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -898,6 +898,17 @@ public class JavacHandlerUtil { return flags; } + public static JCExpression genTypeRef(JavacNode node, String complexName) { + String[] parts = complexName.split("\\."); + if (parts.length > 2 && parts[0].equals("java") && parts[1].equals("lang")) { + String[] subParts = new String[parts.length - 2]; + System.arraycopy(parts, 2, subParts, 0, subParts.length); + return genJavaLangTypeRef(node, subParts); + } + + return chainDots(node, parts); + } + public static JCExpression genJavaLangTypeRef(JavacNode node, String... simpleNames) { if (LombokOptionsFactory.getDelombokOptions(node.getContext()).getFormatPreferences().javaLangAsFqn()) { return chainDots(node, "java", "lang", simpleNames); @@ -1029,15 +1040,27 @@ public class JavacHandlerUtil { } /** - * Generates a new statement that checks if the given variable is null, and if so, throws a {@code NullPointerException} with the + * Generates a new statement that checks if the given variable is null, and if so, throws a specified exception with the * variable name as message. + * + * @param exName The name of the exception to throw; normally {@code java.lang.NullPointerException}. */ - public static JCStatement generateNullCheck(JavacTreeMaker maker, JavacNode variable) { + public static JCStatement generateNullCheck(JavacTreeMaker maker, JavacNode variable, JavacNode source) { + String exceptionType = source.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE); + if (exceptionType == null) { + exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; + } else { + if (!HandlerUtil.isLegalBasicClassReference(exceptionType)) { + source.addWarning("Configuration key contains invalid java type reference '" + exceptionType + "'; use something like 'java.lang.NullPointerException' as value for this key."); + exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; + } + } + JCVariableDecl varDecl = (JCVariableDecl) variable.get(); if (isPrimitive(varDecl.vartype)) return null; Name fieldName = varDecl.name; - JCExpression npe = genJavaLangTypeRef(variable, "NullPointerException"); - JCExpression exception = maker.NewClass(null, List.<JCExpression>nil(), npe, List.<JCExpression>of(maker.Literal(fieldName.toString())), null); + JCExpression exType = genTypeRef(variable, exceptionType); + JCExpression exception = maker.NewClass(null, List.<JCExpression>nil(), exType, List.<JCExpression>of(maker.Literal(fieldName.toString())), null); JCStatement throwStatement = maker.Throw(exception); JCBlock throwBlock = maker.Block(0, List.of(throwStatement)); return maker.If(maker.Binary(CTC_EQUAL, maker.Ident(fieldName), maker.Literal(CTC_BOT, null)), throwBlock, null); diff --git a/test/transform/resource/after-delombok/NonNullWithAlternateException.java b/test/transform/resource/after-delombok/NonNullWithAlternateException.java new file mode 100644 index 00000000..d4a2f657 --- /dev/null +++ b/test/transform/resource/after-delombok/NonNullWithAlternateException.java @@ -0,0 +1,17 @@ +public class NonNullWithAlternateException { + @lombok.NonNull + private String test; + public void testMethod(@lombok.NonNull String arg) { + if (arg == null) { + throw new java.lang.IllegalArgumentException("arg"); + } + System.out.println(arg); + } + @java.lang.SuppressWarnings("all") + public void setTest(@lombok.NonNull final String test) { + if (test == null) { + throw new java.lang.IllegalArgumentException("test"); + } + this.test = test; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/NonNullWithAlternateException.java b/test/transform/resource/after-ecj/NonNullWithAlternateException.java new file mode 100644 index 00000000..43edeb8c --- /dev/null +++ b/test/transform/resource/after-ecj/NonNullWithAlternateException.java @@ -0,0 +1,20 @@ +public class NonNullWithAlternateException { + private @lombok.NonNull @lombok.Setter String test; + public NonNullWithAlternateException() { + super(); + } + public void testMethod(@lombok.NonNull String arg) { + if ((arg == null)) + { + throw new java.lang.IllegalArgumentException("arg"); + } + System.out.println(arg); + } + public @java.lang.SuppressWarnings("all") void setTest(final @lombok.NonNull String test) { + if ((test == null)) + { + throw new java.lang.IllegalArgumentException("test"); + } + this.test = test; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/NonNullWithAlternateException.java b/test/transform/resource/before/NonNullWithAlternateException.java new file mode 100644 index 00000000..780afc39 --- /dev/null +++ b/test/transform/resource/before/NonNullWithAlternateException.java @@ -0,0 +1,9 @@ +//CONF: lombok.nonNull.exceptionType = java.lang.IllegalArgumentException + +public class NonNullWithAlternateException { + @lombok.NonNull @lombok.Setter private String test; + + public void testMethod(@lombok.NonNull String arg) { + System.out.println(arg); + } +} diff --git a/test/transform/resource/before/NonNullWithMistypedException.java b/test/transform/resource/before/NonNullWithMistypedException.java new file mode 100644 index 00000000..6e1fb880 --- /dev/null +++ b/test/transform/resource/before/NonNullWithMistypedException.java @@ -0,0 +1,7 @@ +//CONF: lombok.nonNull.exceptionType = 12345 +//skip compare content: Just testing appropriate generation of error message. + +@lombok.Data +public class NonNullWithMistypedException { + private @lombok.NonNull String test; +} diff --git a/test/transform/resource/messages-delombok/NonNullPlain.java.messages b/test/transform/resource/messages-delombok/NonNullPlain.java.messages index 4033f645..7b0c540b 100644 --- a/test/transform/resource/messages-delombok/NonNullPlain.java.messages +++ b/test/transform/resource/messages-delombok/NonNullPlain.java.messages @@ -1 +1 @@ -8 @NonNull is meaningless on a primitive.
\ No newline at end of file +5 @NonNull is meaningless on a primitive.
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/NonNullWithMistypedException.java.messages b/test/transform/resource/messages-delombok/NonNullWithMistypedException.java.messages new file mode 100644 index 00000000..98bafe6e --- /dev/null +++ b/test/transform/resource/messages-delombok/NonNullWithMistypedException.java.messages @@ -0,0 +1 @@ +4 Configuration key contains invalid java type reference '12345'; use something like 'java.lang.NullPointerException' as value for this key. diff --git a/test/transform/resource/messages-ecj/NonNullWithMistypedException.java.messages b/test/transform/resource/messages-ecj/NonNullWithMistypedException.java.messages new file mode 100644 index 00000000..98bafe6e --- /dev/null +++ b/test/transform/resource/messages-ecj/NonNullWithMistypedException.java.messages @@ -0,0 +1 @@ +4 Configuration key contains invalid java type reference '12345'; use something like 'java.lang.NullPointerException' as value for this key. diff --git a/website/features/NonNull.html b/website/features/NonNull.html index 0e7d064d..4a98504a 100644 --- a/website/features/NonNull.html +++ b/website/features/NonNull.html @@ -42,6 +42,8 @@ <div class="overview confKeys"> <h3>Supported configuration keys:</h3> <dl> + <dt><code>lombok.nonNull.exceptionType</code> = [<code>fully qualified name of an exception</code>] (default: <code>java.lang.NullPointerException</code>). + <dd>When lombok generates a null-check <code>if</code> statement, an exception is thrown, with the parameter / field name as message. By default, this will be a <code>java.lang.NullPointerException</code>, but you can for example put <code>java.lang.IllegalArgumentException</code> in this configuration key to have lombok throw a different exception.</dd> <dt><code>lombok.nonNull.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)</dt> <dd>Lombok will flag any usage of <code>@NonNull</code> as a warning or error if configured.</dd> </dl> |