From 867c3caf61fcc76b7cb8a7356e71858889f85ebf Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Wed, 24 Jul 2019 21:18:36 +0200 Subject: Fixes #2184: NPE on package-info.java without package declaration. --- src/core/lombok/javac/apt/LombokProcessor.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/core/lombok/javac') diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 79db5dec..ed6cdb65 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -389,7 +389,12 @@ public class LombokProcessor extends AbstractProcessor { } private JCCompilationUnit toUnit(Element element) { - TreePath path = trees == null ? null : trees.getPath(element); + TreePath path = null; + if (trees != null) { + try { + path = trees.getPath(element); + } catch (NullPointerException ignore) {} + } if (path == null) return null; return (JCCompilationUnit) path.getCompilationUnit(); -- cgit From ff1c01d9e9e66d898c30939b497490b04fe6163c Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Thu, 25 Jul 2019 13:20:58 +0200 Subject: add comments --- src/core/lombok/javac/apt/LombokProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/core/lombok/javac') diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index ed6cdb65..c32e09d5 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -393,7 +393,11 @@ public class LombokProcessor extends AbstractProcessor { if (trees != null) { try { path = trees.getPath(element); - } catch (NullPointerException ignore) {} + } catch (NullPointerException ignore) { + // Happens if a package-info.java dowsn't conatin a package declaration. + // https://github.com/rzwitserloot/lombok/issues/2184 + // We can safely ignore those, since they do not need any processing + } } if (path == null) return null; -- cgit From 819d1956761f6077fdf897e77c4f6ac47e92104e Mon Sep 17 00:00:00 2001 From: Jacob Middag Date: Thu, 8 Aug 2019 21:14:58 +0200 Subject: [Fixes #2189] Clone type to correctly set annotated type on constructor, getter and setter. --- src/core/lombok/javac/handlers/HandleConstructor.java | 3 ++- src/core/lombok/javac/handlers/HandleGetter.java | 2 +- src/core/lombok/javac/handlers/HandleSetter.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/core/lombok/javac') diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 096963f4..34d2cbfe 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -339,7 +339,8 @@ public class HandleConstructor { Name rawName = field.name; List copyableAnnotations = findCopyableAnnotations(fieldNode); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); - JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, copyableAnnotations), fieldName, field.vartype, null); + JCExpression pType = cloneType(fieldNode.getTreeMaker(), field.vartype, source.get(), source.getContext()); + JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, copyableAnnotations), fieldName, pType, null); params.append(param); if (hasNonNullAnnotations(fieldNode)) { JCStatement nullCheck = generateNullCheck(maker, param, source); diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 7a178f66..f17936eb 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -223,7 +223,7 @@ public class HandleGetter extends JavacAnnotationHandler { JCVariableDecl fieldNode = (JCVariableDecl) field.get(); // Remember the type; lazy will change it - JCExpression methodType = copyType(treeMaker, fieldNode); + JCExpression methodType = cloneType(treeMaker, copyType(treeMaker, fieldNode), source, field.getContext()); // Generate the methodName; lazy will change the field type Name methodName = field.toName(toGetterName(field)); diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index cd8b5d1c..560069ff 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -233,7 +233,8 @@ public class HandleSetter extends JavacAnnotationHandler { List annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext()); - JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(flags, annsOnParam), paramName, fieldDecl.vartype, null); + JCExpression pType = cloneType(treeMaker, fieldDecl.vartype, source.get(), source.getContext()); + JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(flags, annsOnParam), paramName, pType, null); if (!hasNonNullAnnotations(field) && !hasNonNullAnnotations(field, onParam)) { statements.append(treeMaker.Exec(assign)); -- cgit From 15df143df6d35dd64459d717a451a039eb26d761 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 13 Aug 2019 15:04:43 +0200 Subject: [checkerframework] A bit of a shadow feature because the checker framework folks need to do some work on their side. this update makes lombok generate a few checker framework annotations (if configured to do so) which let the checker framework add warnings and errors for example if you misuse builders, or ignore the return values of withers, etc. --- src/core/lombok/javac/handlers/HandleBuilder.java | 69 ++++++++++++---- .../lombok/javac/handlers/HandleConstructor.java | 9 +- .../javac/handlers/HandleEqualsAndHashCode.java | 22 ++++- src/core/lombok/javac/handlers/HandleGetter.java | 9 +- src/core/lombok/javac/handlers/HandleSetter.java | 11 ++- .../lombok/javac/handlers/HandleSuperBuilder.java | 95 ++++++++++++++-------- src/core/lombok/javac/handlers/HandleToString.java | 9 +- src/core/lombok/javac/handlers/HandleWither.java | 10 ++- .../lombok/javac/handlers/JavacHandlerUtil.java | 8 +- .../javac/handlers/JavacSingularsRecipes.java | 40 +++++---- .../handlers/singulars/JavacGuavaSingularizer.java | 5 +- .../JavacJavaUtilListSetSingularizer.java | 5 +- .../singulars/JavacJavaUtilMapSingularizer.java | 5 +- 13 files changed, 206 insertions(+), 91 deletions(-) (limited to 'src/core/lombok/javac') diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 35a6dc26..de2bdde1 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -58,6 +58,7 @@ import lombok.ToString; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.handlers.HandlerUtil; import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.experimental.NonFinal; @@ -102,6 +103,7 @@ public class HandleBuilder extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder"); + CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); Builder builderInstance = annotation.getInstance(); AccessLevel accessForOuters = builderInstance.access(); @@ -434,14 +436,14 @@ public class HandleBuilder extends JavacAnnotationHandler { } for (BuilderFieldData bfd : builderFields) { - makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners); + makeSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, fluent, chain, accessForInners); } { MemberExistsResult methodExists = methodExists(buildMethodName, builderType, -1); if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(buildMethodName, builderType, 0); if (methodExists == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning, accessForInners); + JCMethodDecl md = generateBuildMethod(cfv, tdParent, isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning, accessForInners); if (md != null) { injectMethod(builderType, md); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); @@ -465,7 +467,7 @@ public class HandleBuilder extends JavacAnnotationHandler { if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { - JCMethodDecl md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, annotationNode, tdParent, typeParams, accessForOuters); + JCMethodDecl md = generateBuilderMethod(cfv, isStatic, builderMethodName, builderClassName, annotationNode, tdParent, typeParams, accessForOuters); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); if (md != null) injectMethod(tdParent, md); } @@ -485,7 +487,7 @@ public class HandleBuilder extends JavacAnnotationHandler { } tps = lb.toList(); } - JCMethodDecl md = generateToBuilderMethod(toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast, accessForOuters); + JCMethodDecl md = generateToBuilderMethod(cfv, toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast, accessForOuters); if (md != null) { recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); injectMethod(tdParent, md); @@ -534,7 +536,7 @@ public class HandleBuilder extends JavacAnnotationHandler { } private static final String BUILDER_TEMP_VAR = "builder"; - private JCMethodDecl generateToBuilderMethod(String toBuilderMethodName, String builderClassName, JavacNode type, List typeParams, java.util.List builderFields, boolean fluent, JCAnnotation ast, AccessLevel access) { + private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String toBuilderMethodName, String builderClassName, JavacNode type, List typeParams, java.util.List builderFields, boolean fluent, JCAnnotation ast, AccessLevel access) { // return new ThingieBuilder().setA(this.a).setB(this.b); JavacTreeMaker maker = type.getTreeMaker(); @@ -585,7 +587,8 @@ public class HandleBuilder extends JavacAnnotationHandler { statements.append(maker.Return(invoke)); } JCBlock body = maker.Block(0, statements.toList()); - return maker.MethodDef(maker.Modifiers(toJavacModifier(access)), type.toName(toBuilderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.nil(), List.nil(), List.nil(), body, null); + List annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.nil())) : List.nil(); + return maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(toBuilderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.nil(), List.nil(), List.nil(), body, null); } private JCMethodDecl generateCleanMethod(java.util.List builderFields, JavacNode type, JCTree source) { @@ -617,7 +620,30 @@ public class HandleBuilder extends JavacAnnotationHandler { */ } - private JCMethodDecl generateBuildMethod(JavacNode tdParent, boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List builderFields, JavacNode type, List thrownExceptions, JCTree source, boolean addCleaning, AccessLevel access) { + static List generateBuildArgs(CheckerFrameworkVersion cfv, JavacNode type, java.util.List builderFields) { + if (!cfv.generateCalledMethods()) return List.nil(); + + ArrayList mandatories = new ArrayList(); + for (BuilderFieldData bfd : builderFields) { + if (bfd.singularData == null && bfd.nameOfSetFlag == null) mandatories.add(bfd.name.toString()); + } + + JCExpression arg; + JavacTreeMaker maker = type.getTreeMaker(); + if (mandatories.size() == 0) return List.nil(); + if (mandatories.size() == 1) arg = maker.Literal(mandatories.get(0)); + else { + List elems = List.nil(); + for (int i = mandatories.size() - 1; i >= 0; i--) elems = elems.prepend(maker.Literal(mandatories.get(i))); + arg = maker.NewArray(null, List.nil(), elems); + } + JCAnnotation recvAnno = maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__CALLED), List.of(arg)); + JCClassDecl builderTypeNode = (JCClassDecl) type.get(); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.of(recvAnno)), type.toName("this"), maker.Ident(builderTypeNode.name), null); + return List.of(recv); + } + + private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, JavacNode tdParent, boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List builderFields, JavacNode type, List thrownExceptions, JCTree source, boolean addCleaning, AccessLevel access) { JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; @@ -670,7 +696,9 @@ public class HandleBuilder extends JavacAnnotationHandler { JCBlock body = maker.Block(0, statements.toList()); - return maker.MethodDef(maker.Modifiers(toJavacModifier(access)), type.toName(buildName), returnType, List.nil(), List.nil(), thrownExceptions, body, null); + List annsOnMethod = cfv.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); + List params = generateBuildArgs(cfv, type, builderFields); + return maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(buildName), returnType, List.nil(), params, thrownExceptions, body, null); } public static JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fieldNode, List params) { @@ -685,7 +713,7 @@ public class HandleBuilder extends JavacAnnotationHandler { return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.nil(), List.nil(), body, null); } - public JCMethodDecl generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, JavacNode source, JavacNode type, List typeParams, AccessLevel access) { + public JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String builderMethodName, String builderClassName, JavacNode source, JavacNode type, List typeParams, AccessLevel access) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); @@ -699,7 +727,14 @@ public class HandleBuilder extends JavacAnnotationHandler { JCBlock body = maker.Block(0, List.of(statement)); int modifiers = toJavacModifier(access); if (isStatic) modifiers |= Flags.STATIC; - return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); + JCAnnotation annUnique = cfv.generateUnique() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.nil()) : null; + JCAnnotation annSef = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil()) : null; + List annsOnMethod; + if (annUnique != null && annSef != null) annsOnMethod = List.of(annUnique, annSef); + else if (annUnique != null) annsOnMethod = List.of(annUnique); + else if (annSef != null) annsOnMethod = List.of(annSef); + else annsOnMethod = List.nil(); + return maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); } public void generateBuilderFields(JavacNode builderType, java.util.List builderFields, JCTree source) { @@ -741,16 +776,16 @@ public class HandleBuilder extends JavacAnnotationHandler { for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, source, builderType.getContext()); } - public void makeSetterMethodsForBuilder(JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain, AccessLevel access) { + public void makeSetterMethodsForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain, AccessLevel access) { boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - makeSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode, access); + makeSimpleSetterMethodForBuilder(cfv, builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode, access); } else { - fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), fluent, chain, access); + fieldNode.singularData.getSingularizer().generateMethods(cfv, fieldNode.singularData, deprecate, builderType, source.get(), fluent, chain, access); } } - private void makeSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List annosOnParam, JavacNode originalFieldNode, AccessLevel access) { + private void makeSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List annosOnParam, JavacNode originalFieldNode, AccessLevel access) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { @@ -766,6 +801,12 @@ public class HandleBuilder extends JavacAnnotationHandler { List methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, chain, source, methodAnns, annosOnParam); + if (cfv.generateCalledMethods()) { + JCAnnotation ncAnno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__NOT_CALLED), List.of(maker.Literal(newMethod.getName().toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) builderType.get(); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.of(ncAnno)), builderType.toName("this"), maker.Ident(builderTypeNode.name), null); + newMethod.params = List.of(recv, newMethod.params.get(0)); + } recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext()); copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER); diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 096963f4..9af124b5 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2018 The Project Lombok Authors. + * Copyright (C) 2010-2019 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -56,6 +56,7 @@ import lombok.RequiredArgsConstructor; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.LombokNode; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.delombok.LombokOptionsFactory; import lombok.javac.Javac; import lombok.javac.JavacAST; @@ -222,7 +223,6 @@ public class HandleConstructor { boolean staticConstrRequired = staticName != null && !staticName.equals(""); if (skipIfConstructorExists != SkipIfConstructorExists.NO) { - for (JavacNode child : typeNode.down()) { if (child.getKind() == Kind.ANNOTATION) { boolean skipGeneration = annotationTypeMatches(NoArgsConstructor.class, child) || @@ -247,7 +247,7 @@ public class HandleConstructor { } if (noArgs && noArgsConstructorExists(typeNode)) return; - + ListBuffer argTypes = new ListBuffer(); for (JavacNode fieldNode : fields) { Type mirror = getMirrorForFieldType(fieldNode); @@ -373,7 +373,7 @@ public class HandleConstructor { addConstructorProperties(mods, typeNode, fieldsToParam); } if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor)); - + if (getCheckerFrameworkVersion(source).generateUnique()) mods.annotations = mods.annotations.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__UNIQUE), List.nil())); return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName(""), null, List.nil(), params.toList(), List.nil(), maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source.get(), typeNode.getContext()); @@ -452,6 +452,7 @@ public class HandleConstructor { JCClassDecl type = (JCClassDecl) typeNode.get(); JCModifiers mods = maker.Modifiers(Flags.STATIC | toJavacModifier(level)); + if (getCheckerFrameworkVersion(typeNode).generateUnique()) mods.annotations = mods.annotations.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__UNIQUE), List.nil())); JCExpression returnType, constructorType; diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index e4d7fa7f..2981bfa7 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -59,6 +59,7 @@ import lombok.EqualsAndHashCode; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.configuration.CallSuperType; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.handlers.HandlerUtil; import lombok.core.handlers.HandlerUtil.FieldAccess; import lombok.core.handlers.InclusionExclusionUtils; @@ -203,7 +204,10 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandlernil()); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List annsOnMethod = List.of(overrideAnnotation); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); + if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annsOnMethod); JCExpression returnType = maker.TypeIdent(CTC_INT); ListBuffer statements = new ListBuffer(); @@ -378,7 +382,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandlernil()); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List annsOnMethod = List.of(overrideAnnotation); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); + if (checkerFramework.generateSideEffectFree()) { + annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + } + JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annsOnMethod); JCExpression objectType = genJavaLangTypeRef(typeNode, "Object"); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); @@ -497,7 +506,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandlernil()); + List annsOnMethod = List.nil(); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); + if (checkerFramework.generateSideEffectFree()) { + annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + } + JCModifiers mods = maker.Modifiers(Flags.PROTECTED, annsOnMethod); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); Name canEqualName = typeNode.toName("canEqual"); JCExpression objectType = genJavaLangTypeRef(typeNode, "Object"); diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 7a178f66..f4ac2584 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-2019 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,6 +37,7 @@ import lombok.experimental.Delegate; import lombok.Getter; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -167,6 +168,7 @@ public class HandleGetter extends JavacAnnotationHandler { public void createGetterForField(AccessLevel level, JavacNode fieldNode, JavacNode source, boolean whineIfExists, boolean lazy, List onMethod) { + if (fieldNode.getKind() != Kind.FIELD) { source.addError("@Getter is only supported on a class or a field."); return; @@ -246,9 +248,8 @@ public class HandleGetter extends JavacAnnotationHandler { List copyableAnnotations = findCopyableAnnotations(field); List delegates = findDelegatesAndRemoveFromField(field); List annsOnMethod = copyAnnotations(onMethod).appendList(copyableAnnotations); - if (isFieldDeprecated(field)) { - annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); - } + if (getCheckerFrameworkVersion(field).generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genTypeRef(field, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source, field.getContext()); diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index cd8b5d1c..26820fe6 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -32,6 +32,7 @@ import lombok.ConfigurationKeys; import lombok.Setter; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; @@ -214,7 +215,15 @@ public class HandleSetter extends JavacAnnotationHandler { returnStatement = treeMaker.Return(treeMaker.Ident(field.toName("this"))); } - return createSetter(access, deprecate, field, treeMaker, setterName, paramName, booleanFieldToSet, returnType, returnStatement, source, onMethod, onParam); + JCMethodDecl d = createSetter(access, deprecate, field, treeMaker, setterName, paramName, booleanFieldToSet, returnType, returnStatement, source, onMethod, onParam); + if (shouldReturnThis && getCheckerFrameworkVersion(source).generateReturnsReceiver()) { + List annotations = d.mods.annotations; + if (annotations == null) annotations = List.nil(); + JCAnnotation anno = treeMaker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()); + recursiveSetGeneratedBy(anno, source.get(), field.getContext()); + d.mods.annotations = annotations.prepend(anno); + } + return d; } public static JCMethodDecl createSetter(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, JCExpression methodType, JCStatement returnStatement, JavacNode source, List onMethod, List onParam) { diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index a5c492a1..0f809571 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -62,6 +62,7 @@ import lombok.ConfigurationKeys; import lombok.Singular; import lombok.ToString; import lombok.core.AST.Kind; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.core.handlers.HandlerUtil; @@ -93,7 +94,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); - + CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); SuperBuilder superbuilderAnnotation = annotation.getInstance(); deleteAnnotationIfNeccessary(annotationNode, SuperBuilder.class); @@ -284,16 +285,16 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } // Generate abstract self() and build() methods in the abstract builder. - JCMethodDecl asm = generateAbstractSelfMethod(tdParent, superclassBuilderClassExpression != null, builderGenericName); + JCMethodDecl asm = generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClassExpression != null, builderGenericName); recursiveSetGeneratedBy(asm, ast, annotationNode.getContext()); injectMethod(builderType, asm); - JCMethodDecl abm = generateAbstractBuildMethod(tdParent, buildMethodName, superclassBuilderClassExpression != null, classGenericName); + JCMethodDecl abm = generateAbstractBuildMethod(cfv, tdParent, buildMethodName, builderFields, superclassBuilderClassExpression != null, classGenericName); recursiveSetGeneratedBy(abm, ast, annotationNode.getContext()); injectMethod(builderType, abm); // Create the setter methods in the abstract builder. for (BuilderFieldData bfd : builderFields) { - generateSetterMethodsForBuilder(builderType, bfd, annotationNode, builderGenericName); + generateSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, builderGenericName); } // Create the toString() method for the abstract builder. @@ -339,18 +340,18 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { if (cd != null) injectMethod(builderImplType, cd); // Create the self() and build() methods in the BuilderImpl. - JCMethodDecl selfMethod = generateSelfMethod(builderImplType, typeParams); + JCMethodDecl selfMethod = generateSelfMethod(cfv, builderImplType, typeParams); recursiveSetGeneratedBy(selfMethod, ast, annotationNode.getContext()); injectMethod(builderImplType, selfMethod); if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl buildMethod = generateBuildMethod(buildMethodName, tdParent, builderImplType, thrownExceptions); + JCMethodDecl buildMethod = generateBuildMethod(cfv, buildMethodName, tdParent, builderImplType, builderFields, thrownExceptions); recursiveSetGeneratedBy(buildMethod, ast, annotationNode.getContext()); injectMethod(builderImplType, buildMethod); } } // Generate a constructor in the annotated class that takes a builder as argument. - generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, + generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, superclassBuilderClassExpression != null); if (isAbstract) { @@ -362,7 +363,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { // Allow users to specify their own builder() methods, e.g., to provide default values. if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { - JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); + JCMethodDecl builderMethod = generateBuilderMethod(cfv, builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext()); if (builderMethod != null) injectMethod(tdParent, builderMethod); } @@ -374,7 +375,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { annotationNode.addWarning("Not generating toBuilder() as it already exists."); return; case NOT_EXISTS: - JCMethodDecl md = generateToBuilderMethod(builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); + JCMethodDecl md = generateToBuilderMethod(cfv, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); if (md != null) { recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); injectMethod(tdParent, md); @@ -483,7 +484,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { * constructor with the builder as argument. Requires * {@code builderClassAsParameter != null}. */ - private void generateBuilderBasedConstructor(JavacNode typeNode, List typeParams, java.util.List builderFields, JavacNode source, String builderClassName, boolean callBuilderBasedSuperConstructor) { + private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, JavacNode typeNode, List typeParams, java.util.List builderFields, JavacNode source, String builderClassName, boolean callBuilderBasedSuperConstructor) { JavacTreeMaker maker = typeNode.getTreeMaker(); AccessLevel level = AccessLevel.PROTECTED; @@ -519,7 +520,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } } - JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.nil()); + List annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); + JCModifiers mods = maker.Modifiers(toJavacModifier(level), annsOnMethod); // Create a constructor that has just the builder as parameter. ListBuffer params = new ListBuffer(); @@ -551,7 +553,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { injectMethod(typeNode, constr, null, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); } - private JCMethodDecl generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List typeParams) { + private JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, String builderMethodName, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); @@ -573,7 +575,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { typeParameterNames.add(wildcard); JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList()); - return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); + List annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); + return maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); } /** @@ -584,7 +587,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { * } * */ - private JCMethodDecl generateToBuilderMethod(String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List typeParams) { + private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); @@ -607,7 +610,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { typeParameterNames.add(wildcard); JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList()); - return maker.MethodDef(maker.Modifiers(modifiers), type.toName(TO_BUILDER_METHOD_NAME), returnType, List.nil(), List.nil(), List.nil(), body, null); + List annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); + return maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(TO_BUILDER_METHOD_NAME), returnType, List.nil(), List.nil(), List.nil(), body, null); } /** @@ -737,25 +741,34 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return exec; } - private JCMethodDecl generateAbstractSelfMethod(JavacNode type, boolean override, String builderGenericName) { + private JCMethodDecl generateAbstractSelfMethod(CheckerFrameworkVersion cfv, JavacNode type, boolean override, String builderGenericName) { JavacTreeMaker maker = type.getTreeMaker(); List annotations = List.nil(); - if (override) { - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); - annotations = List.of(overrideAnnotation); - } + JCAnnotation overrideAnnotation = override ? maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()) : null; + JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; + JCAnnotation sefAnnotation = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil()) : null; + if (sefAnnotation != null) annotations = annotations.prepend(sefAnnotation); + if (rrAnnotation != null) annotations = annotations.prepend(rrAnnotation); + if (overrideAnnotation != null) annotations = annotations.prepend(overrideAnnotation); JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED | Flags.ABSTRACT, annotations); Name name = type.toName(SELF_METHOD); JCExpression returnType = maker.Ident(type.toName(builderGenericName)); - + return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), null, null); } - private JCMethodDecl generateSelfMethod(JavacNode builderImplType, List typeParams) { + private JCMethodDecl generateSelfMethod(CheckerFrameworkVersion cfv, JavacNode builderImplType, List typeParams) { JavacTreeMaker maker = builderImplType.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(builderImplType, "Override"), List.nil()); - JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, List.of(overrideAnnotation)); + JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; + JCAnnotation sefAnnotation = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil()) : null; + List annsOnMethod = List.nil(); + if (sefAnnotation != null) annsOnMethod = annsOnMethod.prepend(sefAnnotation); + if (rrAnnotation != null) annsOnMethod = annsOnMethod.prepend(rrAnnotation); + annsOnMethod = annsOnMethod.prepend(overrideAnnotation); + + JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, annsOnMethod); Name name = builderImplType.toName(SELF_METHOD); JCExpression returnType = namePlusTypeParamsToTypeReference(maker, builderImplType.toName(builderImplType.getName()), typeParams); @@ -765,21 +778,23 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), body, null); } - private JCMethodDecl generateAbstractBuildMethod(JavacNode type, String methodName, boolean override, String classGenericName) { + private JCMethodDecl generateAbstractBuildMethod(CheckerFrameworkVersion cfv, JavacNode type, String methodName, java.util.List builderFields, boolean override, String classGenericName) { JavacTreeMaker maker = type.getTreeMaker(); List annotations = List.nil(); if (override) { JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); annotations = List.of(overrideAnnotation); } + if (cfv.generateSideEffectFree()) annotations = annotations.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC | Flags.ABSTRACT, annotations); Name name = type.toName(methodName); JCExpression returnType = maker.Ident(type.toName(classGenericName)); - return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), null, null); + List params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); + return maker.MethodDef(modifiers, name, returnType, List.nil(), params, List.nil(), null, null); } - private JCMethodDecl generateBuildMethod(String buildName, JavacNode returnType, JavacNode type, List thrownExceptions) { + private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, String buildName, JavacNode returnType, JavacNode type, java.util.List builderFields, List thrownExceptions) { JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; @@ -793,9 +808,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { JCBlock body = maker.Block(0, statements.toList()); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); - JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List annsOnMethod = List.of(overrideAnnotation); + if (cfv.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, annsOnMethod); - return maker.MethodDef(modifiers, type.toName(buildName), cloneSelfType(returnType), List.nil(), List.nil(), thrownExceptions, body, null); + List params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); + return maker.MethodDef(modifiers, type.toName(buildName), cloneSelfType(returnType), List.nil(), params, thrownExceptions, body, null); } private JCMethodDecl generateCleanMethod(java.util.List builderFields, JavacNode type, JCTree source) { @@ -852,7 +870,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, source, builderType.getContext()); } - private void generateSetterMethodsForBuilder(final JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, final String builderGenericName) { + private void generateSetterMethodsForBuilder(CheckerFrameworkVersion cfv, final JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, final String builderGenericName) { boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); final JavacTreeMaker maker = builderType.getTreeMaker(); ExpressionMaker returnTypeMaker = new ExpressionMaker() { @Override public JCExpression make() { @@ -864,13 +882,13 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { }}; if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - generateSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, true, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations, fieldNode.originalFieldNode); + generateSimpleSetterMethodForBuilder(cfv, builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, true, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations, fieldNode.originalFieldNode); } else { - fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); + fieldNode.singularData.getSingularizer().generateMethods(cfv, fieldNode.singularData, deprecate, builderType, source.get(), true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); } } - private void generateSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, JCExpression returnType, JCStatement returnStatement, List annosOnParam, JavacNode originalFieldNode) { + private void generateSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, JCExpression returnType, JCStatement returnStatement, List annosOnParam, JavacNode originalFieldNode) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { @@ -886,6 +904,19 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { List methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, returnType, returnStatement, source, methodAnns, annosOnParam); + if (cfv.generateCalledMethods()) { + JCAnnotation ncAnno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__NOT_CALLED), List.of(maker.Literal(newMethod.getName().toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) builderType.get(); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.of(ncAnno)), builderType.toName("this"), maker.Ident(builderTypeNode.name), null); + newMethod.params = List.of(recv, newMethod.params.get(0)); + } + if (cfv.generateReturnsReceiver()) { + List annotations = newMethod.mods.annotations; + if (annotations == null) annotations = List.nil(); + JCAnnotation anno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()); + recursiveSetGeneratedBy(anno, source.get(), builderType.getContext()); + newMethod.mods.annotations = annotations.prepend(anno); + } injectMethod(builderType, newMethod); } diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index 3780da79..d0d36e06 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,7 @@ import lombok.ConfigurationKeys; import lombok.ToString; import lombok.core.AnnotationValues; import lombok.core.configuration.CallSuperType; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.AST.Kind; import lombok.core.handlers.InclusionExclusionUtils; import lombok.core.handlers.InclusionExclusionUtils.Included; @@ -93,7 +94,7 @@ public class HandleToString extends JavacAnnotationHandler { boolean includeFieldNames = true; try { Boolean configuration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES); - includeFieldNames = configuration != null ? configuration : ((Boolean)ToString.class.getMethod("includeFieldNames").getDefaultValue()).booleanValue(); + includeFieldNames = configuration != null ? configuration : ((Boolean) ToString.class.getMethod("includeFieldNames").getDefaultValue()).booleanValue(); } catch (Exception ignore) {} Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS); @@ -160,7 +161,9 @@ public class HandleToString extends JavacAnnotationHandler { JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.nil()); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List annsOnMethod = List.of(overrideAnnotation); + if (getCheckerFrameworkVersion(typeNode).generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annsOnMethod); JCExpression returnType = genJavaLangTypeRef(typeNode, "String"); boolean first = true; diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java index 33c4dec2..9c95cb78 100644 --- a/src/core/lombok/javac/handlers/HandleWither.java +++ b/src/core/lombok/javac/handlers/HandleWither.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-2019 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,7 @@ import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.experimental.Wither; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; @@ -279,10 +280,11 @@ public class HandleWither extends JavacAnnotationHandler { JCExpression annotationMethodDefaultValue = null; List annsOnMethod = copyAnnotations(onMethod); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(source); + if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + + if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); - if (isFieldDeprecated(field)) { - annsOnMethod = annsOnMethod.prepend(maker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); - } if (makeAbstract) access = access | Flags.ABSTRACT; JCMethodDecl decl = recursiveSetGeneratedBy(maker.MethodDef(maker.Modifiers(access, annsOnMethod), methodName, returnType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source.get(), field.getContext()); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 5f0f39b0..f23a894a 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -93,6 +93,7 @@ import lombok.core.AnnotationValues.AnnotationValue; import lombok.core.CleanupTask; import lombok.core.LombokImmutableList; import lombok.core.TypeResolver; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.configuration.NullCheckExceptionType; import lombok.core.configuration.TypeName; import lombok.core.handlers.HandlerUtil; @@ -330,6 +331,11 @@ public class JavacHandlerUtil { return false; } + public static CheckerFrameworkVersion getCheckerFrameworkVersion(JavacNode node) { + CheckerFrameworkVersion cfv = node.getAst().readConfiguration(ConfigurationKeys.CHECKER_FRAMEWORK); + return cfv == null ? CheckerFrameworkVersion.NONE : cfv; + } + /** * Returns if a node is marked deprecated (as picked up on by the parser). * @param node the node to check (type, method, or field decl). @@ -1266,7 +1272,7 @@ public class JavacHandlerUtil { } } - private static void addAnnotation(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context, String annotationTypeFqn, JCExpression arg) { + public static void addAnnotation(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context, String annotationTypeFqn, JCExpression arg) { boolean isJavaLangBased; String simpleName; { int idx = annotationTypeFqn.lastIndexOf('.'); diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index a5895951..341d44df 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -37,6 +37,7 @@ import lombok.ConfigurationKeys; import lombok.core.LombokImmutableList; import lombok.core.SpiLoadUtil; import lombok.core.TypeLibrary; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.handlers.HandlerUtil; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -163,9 +164,12 @@ public class JavacSingularsRecipes { return this; } - protected JCModifiers makeMods(JavacTreeMaker maker, JavacNode node, boolean deprecate, AccessLevel access) { - if (deprecate) return maker.Modifiers(toJavacModifier(access), List.of(maker.Annotation(genJavaLangTypeRef(node, "Deprecated"), List.nil()))); - return maker.Modifiers(toJavacModifier(access)); + protected JCModifiers makeMods(JavacTreeMaker maker, CheckerFrameworkVersion cfv, JavacNode node, boolean deprecate, AccessLevel access) { + JCAnnotation deprecateAnn = deprecate ? maker.Annotation(genJavaLangTypeRef(node, "Deprecated"), List.nil()) : null; + JCAnnotation rrAnn = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(node, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; + + List annsOnMethod = (deprecateAnn != null && rrAnn != null) ? List.of(deprecateAnn, rrAnn) : deprecateAnn != null ? List.of(deprecateAnn) : rrAnn != null ? List.of(rrAnn) : List.nil(); + return maker.Modifiers(toJavacModifier(access), annsOnMethod); } /** Checks if any of the to-be-generated nodes (fields, methods) already exist. If so, errors on these (singulars don't support manually writing some of it, and returns true). */ @@ -220,7 +224,7 @@ public class JavacSingularsRecipes { * If you need more control over the return type and value, use * {@link #generateMethods(SingularData, boolean, JavacNode, JCTree, boolean, ExpressionMaker, StatementMaker)}. */ - public void generateMethods(SingularData data, boolean deprecate, final JavacNode builderType, JCTree source, boolean fluent, final boolean chain, AccessLevel access) { + public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, final JavacNode builderType, JCTree source, boolean fluent, final boolean chain, AccessLevel access) { final JavacTreeMaker maker = builderType.getTreeMaker(); ExpressionMaker returnTypeMaker = new ExpressionMaker() { @Override public JCExpression make() { @@ -233,26 +237,26 @@ public class JavacSingularsRecipes { return chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; }}; - generateMethods(data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); + generateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); } /** * Generates the singular, plural, and clear methods for the given {@link SingularData}. * Uses the given {@code returnTypeMaker} and {@code returnStatementMaker} for the generated methods. */ - public abstract void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access); + public abstract void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access); - protected void doGenerateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + protected void doGenerateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { JavacTreeMaker maker = builderType.getTreeMaker(); - generateSingularMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent, access); - generatePluralMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent, access); - generateClearMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, access); + generateSingularMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent, access); + generatePluralMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent, access); + generateClearMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, access); } - private void finishAndInjectMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, AccessLevel access) { + private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, AccessLevel access) { if (returnStatement != null) statements.append(returnStatement); JCBlock body = maker.Block(0, statements.toList()); - JCModifiers mods = makeMods(maker, builderType, deprecate, access); + JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access); List typeParams = List.nil(); List thrown = List.nil(); JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, jcVariableDecls, thrown, body, null); @@ -260,25 +264,25 @@ public class JavacSingularsRecipes { injectMethod(builderType, method); } - private void generateClearMethod(boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, AccessLevel access) { + private void generateClearMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, AccessLevel access) { JCStatement clearStatement = generateClearStatements(maker, data, builderType); ListBuffer statements = new ListBuffer