diff options
Diffstat (limited to 'src/core/lombok/javac')
14 files changed, 289 insertions, 157 deletions
diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 79db5dec..c32e09d5 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -389,7 +389,16 @@ 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) { + // 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; return (JCCompilationUnit) path.getCompilationUnit(); diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index e447ace7..da40692e 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,7 +103,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { @Override public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder"); - + CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); + Builder builderInstance = annotation.getInstance(); AccessLevel accessForOuters = builderInstance.access(); if (accessForOuters == null) accessForOuters = AccessLevel.PUBLIC; @@ -434,14 +436,14 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } for (BuilderFieldData bfd : builderFields) { - makePrefixedSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, builderInstance.setterPrefix()); + makePrefixedSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, fluent, chain, accessForInners, builderInstance.setterPrefix()); } { 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<Builder> { 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<Builder> { } 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<Builder> { } private static final String BUILDER_TEMP_VAR = "builder"; - private JCMethodDecl generateToBuilderMethod(String toBuilderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, boolean fluent, JCAnnotation ast, AccessLevel access) { + private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String toBuilderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, boolean fluent, JCAnnotation ast, AccessLevel access) { // return new ThingieBuilder<A, B>().setA(this.a).setB(this.b); JavacTreeMaker maker = type.getTreeMaker(); @@ -585,7 +587,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + List<JCAnnotation> annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + return maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(toBuilderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) { @@ -617,7 +620,30 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { */ } - private JCMethodDecl generateBuildMethod(JavacNode tdParent, boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning, AccessLevel access) { + static List<JCVariableDecl> generateBuildArgs(CheckerFrameworkVersion cfv, JavacNode type, java.util.List<BuilderFieldData> builderFields) { + if (!cfv.generateCalledMethods()) return List.<JCVariableDecl>nil(); + + ArrayList<String> mandatories = new ArrayList<String>(); + 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.<JCVariableDecl>nil(); + if (mandatories.size() == 1) arg = maker.Literal(mandatories.get(0)); + else { + List<JCExpression> 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.<JCExpression>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.<JCAnnotation>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<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning, AccessLevel access) { JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; @@ -670,7 +696,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCBlock body = maker.Block(0, statements.toList()); - return maker.MethodDef(maker.Modifiers(toJavacModifier(access)), type.toName(buildName), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); + List<JCAnnotation> annsOnMethod = cfv.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + List<JCVariableDecl> params = generateBuildArgs(cfv, type, builderFields); + return maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(buildName), returnType, List.<JCTypeParameter>nil(), params, thrownExceptions, body, null); } public static JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fieldNode, List<JCTypeParameter> params) { @@ -685,7 +713,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } - public JCMethodDecl generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams, AccessLevel access) { + public JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String builderMethodName, String builderClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams, AccessLevel access) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); @@ -699,7 +727,14 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCBlock body = maker.Block(0, List.<JCStatement>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.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + JCAnnotation annUnique = cfv.generateUnique() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil()) : null; + JCAnnotation annSef = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()) : null; + List<JCAnnotation> 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.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } public void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JCTree source) { @@ -741,16 +776,16 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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<JCAnnotation> 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<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { @@ -772,17 +807,17 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { injectMethod(builderType, newMethod); } - public void makePrefixedSetterMethodsForBuilder(JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain, AccessLevel access, String prefix) { + public void makePrefixedSetterMethodsForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain, AccessLevel access, String prefix) { boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - makePrefixedSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode, access, prefix); + makePrefixedSetterMethodForBuilder(cfv, builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode, access, prefix); } else { // TODO prefixed version - 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 makePrefixedSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access, String prefix) { + private void makePrefixedSetterMethodForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access, String prefix) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { @@ -804,6 +839,12 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { List<JCAnnotation> 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.<JCExpression>of(maker.Literal(newMethod.getName().toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) builderType.get(); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.<JCAnnotation>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..4d7c61ad 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<Type> argTypes = new ListBuffer<Type>(); for (JavacNode fieldNode : fields) { Type mirror = getMirrorForFieldType(fieldNode); @@ -339,7 +339,8 @@ public class HandleConstructor { Name rawName = field.name; List<JCAnnotation> 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); @@ -373,7 +374,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.<JCExpression>nil())); 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.get(), typeNode.getContext()); @@ -452,6 +453,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.<JCExpression>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 JavacAnnotationHandler<EqualsAndHas JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); + if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annsOnMethod); JCExpression returnType = maker.TypeIdent(CTC_INT); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); @@ -378,7 +382,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas Name thisName = typeNode.toName("this"); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); + if (checkerFramework.generateSideEffectFree()) { + annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>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 JavacAnnotationHandler<EqualsAndHas */ JavacTreeMaker maker = typeNode.getTreeMaker(); - JCModifiers mods = maker.Modifiers(Flags.PROTECTED, List.<JCAnnotation>nil()); + List<JCAnnotation> annsOnMethod = List.nil(); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); + if (checkerFramework.generateSideEffectFree()) { + annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>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..681865df 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<Getter> { public void createGetterForField(AccessLevel level, JavacNode fieldNode, JavacNode source, boolean whineIfExists, boolean lazy, List<JCAnnotation> onMethod) { + if (fieldNode.getKind() != Kind.FIELD) { source.addError("@Getter is only supported on a class or a field."); return; @@ -223,7 +225,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { 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)); @@ -246,9 +248,8 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(field); List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field); List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod).appendList(copyableAnnotations); - if (isFieldDeprecated(field)) { - annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil())); - } + if (getCheckerFrameworkVersion(field).generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genTypeRef(field, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>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..926e94d9 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<Setter> { 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<JCAnnotation> annotations = d.mods.annotations; + if (annotations == null) annotations = List.nil(); + JCAnnotation anno = treeMaker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>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<JCAnnotation> onMethod, List<JCAnnotation> onParam) { @@ -233,7 +242,8 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { List<JCAnnotation> 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)); 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<SuperBuilder> { @Override public void handle(AnnotationValues<SuperBuilder> 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<SuperBuilder> { } // 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<SuperBuilder> { 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<SuperBuilder> { // 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<SuperBuilder> { 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<SuperBuilder> { * constructor with the builder as argument. Requires * {@code builderClassAsParameter != null}. */ - private void generateBuilderBasedConstructor(JavacNode typeNode, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, JavacNode source, String builderClassName, boolean callBuilderBasedSuperConstructor) { + private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, JavacNode typeNode, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, JavacNode source, String builderClassName, boolean callBuilderBasedSuperConstructor) { JavacTreeMaker maker = typeNode.getTreeMaker(); AccessLevel level = AccessLevel.PROTECTED; @@ -519,7 +520,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } } - JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil()); + List<JCAnnotation> annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + JCModifiers mods = maker.Modifiers(toJavacModifier(level), annsOnMethod); // Create a constructor that has just the builder as parameter. ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); @@ -551,7 +553,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { injectMethod(typeNode, constr, null, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); } - private JCMethodDecl generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { + private JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, String builderMethodName, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); @@ -573,7 +575,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { 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.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + List<JCAnnotation> annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + return maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } /** @@ -584,7 +587,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { * } * </pre> */ - private JCMethodDecl generateToBuilderMethod(String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { + private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); @@ -607,7 +610,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { 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.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + List<JCAnnotation> annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + return maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(TO_BUILDER_METHOD_NAME), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } /** @@ -737,25 +741,34 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { 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<JCAnnotation> annotations = List.nil(); - if (override) { - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()); - annotations = List.of(overrideAnnotation); - } + JCAnnotation overrideAnnotation = override ? maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()) : null; + JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()) : null; + JCAnnotation sefAnnotation = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>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.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null); } - private JCMethodDecl generateSelfMethod(JavacNode builderImplType, List<JCTypeParameter> typeParams) { + private JCMethodDecl generateSelfMethod(CheckerFrameworkVersion cfv, JavacNode builderImplType, List<JCTypeParameter> typeParams) { JavacTreeMaker maker = builderImplType.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(builderImplType, "Override"), List.<JCExpression>nil()); - JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, List.of(overrideAnnotation)); + JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()) : null; + JCAnnotation sefAnnotation = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()) : null; + List<JCAnnotation> 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<SuperBuilder> { return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>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<BuilderFieldData> builderFields, boolean override, String classGenericName) { JavacTreeMaker maker = type.getTreeMaker(); List<JCAnnotation> annotations = List.nil(); if (override) { JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()); annotations = List.of(overrideAnnotation); } + if (cfv.generateSideEffectFree()) annotations = annotations.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>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.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null); + List<JCVariableDecl> params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); + return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), null, null); } - private JCMethodDecl generateBuildMethod(String buildName, JavacNode returnType, JavacNode type, List<JCExpression> thrownExceptions) { + private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, String buildName, JavacNode returnType, JavacNode type, java.util.List<BuilderFieldData> builderFields, List<JCExpression> thrownExceptions) { JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; @@ -793,9 +808,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { JCBlock body = maker.Block(0, statements.toList()); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()); - JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation); + if (cfv.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, annsOnMethod); - return maker.MethodDef(modifiers, type.toName(buildName), cloneSelfType(returnType), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); + List<JCVariableDecl> params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); + return maker.MethodDef(modifiers, type.toName(buildName), cloneSelfType(returnType), List.<JCTypeParameter>nil(), params, thrownExceptions, body, null); } private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) { @@ -852,7 +870,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { 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<SuperBuilder> { }}; 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<JCAnnotation> 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<JCAnnotation> annosOnParam, JavacNode originalFieldNode) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { @@ -886,6 +904,19 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { List<JCAnnotation> 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.<JCExpression>of(maker.Literal(newMethod.getName().toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) builderType.get(); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.<JCAnnotation>of(ncAnno)), builderType.toName("this"), maker.Ident(builderTypeNode.name), null); + newMethod.params = List.of(recv, newMethod.params.get(0)); + } + if (cfv.generateReturnsReceiver()) { + List<JCAnnotation> annotations = newMethod.mods.annotations; + if (annotations == null) annotations = List.nil(); + JCAnnotation anno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>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<ToString> { 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<ToString> { JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); + List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation); + if (getCheckerFrameworkVersion(typeNode).generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>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/HandleWith.java index 33c4dec2..7b2417da 100644 --- a/src/core/lombok/javac/handlers/HandleWither.java +++ b/src/core/lombok/javac/handlers/HandleWith.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 @@ -29,9 +29,10 @@ import java.util.Collection; import lombok.AccessLevel; import lombok.ConfigurationKeys; +import lombok.With; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; -import lombok.experimental.Wither; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -59,13 +60,13 @@ import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; /** - * Handles the {@code lombok.experimental.Wither} annotation for javac. + * Handles the {@code lombok.With} annotation for javac. */ @ProviderFor(JavacAnnotationHandler.class) -public class HandleWither extends JavacAnnotationHandler<Wither> { - public void generateWitherForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelWither) { - if (checkForTypeLevelWither) { - if (hasAnnotation(Wither.class, typeNode)) { +public class HandleWith extends JavacAnnotationHandler<With> { + public void generateWithForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelWith) { + if (checkForTypeLevelWith) { + if (hasAnnotation(With.class, typeNode)) { //The annotation will make it happen, so we can skip it. return; } @@ -77,7 +78,7 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0; if (typeDecl == null || notAClass) { - errorNode.addError("@Wither is only supported on a class or a field."); + errorNode.addError("@With is only supported on a class or a field."); return; } @@ -91,105 +92,105 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { //Skip final initialized fields. if ((fieldDecl.mods.flags & Flags.FINAL) != 0 && fieldDecl.init != null) continue; - generateWitherForField(field, errorNode.get(), level); + generateWithForField(field, errorNode.get(), level); } } /** - * Generates a wither on the stated field. + * Generates a with on the stated field. * * Used by {@link HandleValue}. * * The difference between this call and the handle method is as follows: * - * If there is a {@code lombok.experimental.Wither} annotation on the field, it is used and the + * If there is a {@code lombok.With} annotation on the field, it is used and the * same rules apply (e.g. warning if the method already exists, stated access level applies). - * If not, the wither is still generated if it isn't already there, though there will not + * If not, the with 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. * - * @param fieldNode The node representing the field you want a wither for. - * @param pos The node responsible for generating the wither (the {@code @Value} or {@code @Wither} annotation). + * @param fieldNode The node representing the field you want a with for. + * @param pos The node responsible for generating the with (the {@code @Value} or {@code @With} annotation). */ - public void generateWitherForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level) { - if (hasAnnotation(Wither.class, fieldNode)) { + public void generateWithForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level) { + if (hasAnnotation(With.class, fieldNode)) { //The annotation will make it happen, so we can skip it. return; } - createWitherForField(level, fieldNode, fieldNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); + createWithForField(level, fieldNode, fieldNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); } - @Override public void handle(AnnotationValues<Wither> annotation, JCAnnotation ast, JavacNode annotationNode) { - handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.WITHER_FLAG_USAGE, "@Wither"); + @Override public void handle(AnnotationValues<With> annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.WITH_FLAG_USAGE, "@With"); Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields(); - deleteAnnotationIfNeccessary(annotationNode, Wither.class); + deleteAnnotationIfNeccessary(annotationNode, With.class, "lombok.experimental.Wither"); deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode node = annotationNode.up(); AccessLevel level = annotation.getInstance().value(); if (level == AccessLevel.NONE || node == null) return; - List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Wither(onMethod", annotationNode); - List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Wither(onParam", annotationNode); + List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@With(onMethod", annotationNode); + List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@With(onParam", annotationNode); switch (node.getKind()) { case FIELD: - createWitherForFields(level, fields, annotationNode, true, onMethod, onParam); + createWithForFields(level, fields, annotationNode, true, onMethod, onParam); break; case TYPE: - if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @Wither on a type."); - if (!onParam.isEmpty()) annotationNode.addError("'onParam' is not supported for @Wither on a type."); - generateWitherForType(node, annotationNode, level, false); + if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @With on a type."); + if (!onParam.isEmpty()) annotationNode.addError("'onParam' is not supported for @With on a type."); + generateWithForType(node, annotationNode, level, false); break; } } - public void createWitherForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + public void createWithForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { for (JavacNode fieldNode : fieldNodes) { - createWitherForField(level, fieldNode, errorNode, whineIfExists, onMethod, onParam); + createWithForField(level, fieldNode, errorNode, whineIfExists, onMethod, onParam); } } - public void createWitherForField(AccessLevel level, JavacNode fieldNode, JavacNode source, boolean strictMode, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + public void createWithForField(AccessLevel level, JavacNode fieldNode, JavacNode source, boolean strictMode, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { JavacNode typeNode = fieldNode.up(); boolean makeAbstract = typeNode != null && typeNode.getKind() == Kind.TYPE && (((JCClassDecl) typeNode.get()).mods.flags & Flags.ABSTRACT) != 0; if (fieldNode.getKind() != Kind.FIELD) { - fieldNode.addError("@Wither is only supported on a class or a field."); + fieldNode.addError("@With is only supported on a class or a field."); return; } - JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get(); - String methodName = toWitherName(fieldNode); + JCVariableDecl fieldDecl = (JCVariableDecl) fieldNode.get(); + String methodName = toWithName(fieldNode); if (methodName == null) { - fieldNode.addWarning("Not generating wither for this field: It does not fit your @Accessors prefix list."); + fieldNode.addWarning("Not generating a withX method for this field: It does not fit your @Accessors prefix list."); return; } if ((fieldDecl.mods.flags & Flags.STATIC) != 0) { if (strictMode) { - fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for static fields."); + fieldNode.addWarning("Not generating " + methodName + " for this field: With methods cannot be generated for static fields."); } return; } if ((fieldDecl.mods.flags & Flags.FINAL) != 0 && fieldDecl.init != null) { if (strictMode) { - fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for final, initialized fields."); + fieldNode.addWarning("Not generating " + methodName + " for this field: With methods cannot be generated for final, initialized fields."); } return; } if (fieldDecl.name.toString().startsWith("$")) { if (strictMode) { - fieldNode.addWarning("Not generating wither for this field: Withers cannot be generated for fields starting with $."); + fieldNode.addWarning("Not generating " + methodName + " for this field: With methods cannot be generated for fields starting with $."); } return; } - for (String altName : toAllWitherNames(fieldNode)) { + for (String altName : toAllWithNames(fieldNode)) { switch (methodExists(altName, fieldNode, false, 1)) { case EXISTS_BY_LOMBOK: return; @@ -209,22 +210,22 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { long access = toJavacModifier(level); - JCMethodDecl createdWither = createWither(access, fieldNode, fieldNode.getTreeMaker(), source, onMethod, onParam, makeAbstract); + JCMethodDecl createdWith = createWith(access, fieldNode, fieldNode.getTreeMaker(), source, onMethod, onParam, makeAbstract); ClassSymbol sym = ((JCClassDecl) fieldNode.up().get()).sym; Type returnType = sym == null ? null : sym.type; - injectMethod(typeNode, createdWither, List.<Type>of(getMirrorForFieldType(fieldNode)), returnType); + injectMethod(typeNode, createdWith, List.<Type>of(getMirrorForFieldType(fieldNode)), returnType); } - public JCMethodDecl createWither(long access, JavacNode field, JavacTreeMaker maker, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam, boolean makeAbstract) { - String witherName = toWitherName(field); - if (witherName == null) return null; + public JCMethodDecl createWith(long access, JavacNode field, JavacTreeMaker maker, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam, boolean makeAbstract) { + String withName = toWithName(field); + if (withName == null) return null; JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(field); - Name methodName = field.toName(witherName); + Name methodName = field.toName(withName); JCExpression returnType = cloneSelfType(field); @@ -279,14 +280,15 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { JCExpression annotationMethodDefaultValue = null; List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod); + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(source); + if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + + if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil())); - if (isFieldDeprecated(field)) { - annsOnMethod = annsOnMethod.prepend(maker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>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()); - copyJavadoc(field, decl, CopyJavadoc.WITHER); + methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source.get(), field.getContext()); + copyJavadoc(field, decl, CopyJavadoc.WITH); return decl; } } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 5f0f39b0..d12a980f 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). @@ -584,20 +590,20 @@ public class JavacHandlerUtil { } /** - * Translates the given field into all possible wither names. - * Convenient wrapper around {@link TransformationsUtil#toAllWitherNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + * Translates the given field into all possible with names. + * Convenient wrapper around {@link TransformationsUtil#toAllWithNames(lombok.core.AnnotationValues, CharSequence, boolean)}. */ - public static java.util.List<String> toAllWitherNames(JavacNode field) { - return HandlerUtil.toAllWitherNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); + public static java.util.List<String> toAllWithNames(JavacNode field) { + return HandlerUtil.toAllWithNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } /** - * @return the likely wither name for the stated field. (e.g. private boolean foo; to withFoo). + * @return the likely with name for the stated field. (e.g. private boolean foo; to withFoo). * - * Convenient wrapper around {@link TransformationsUtil#toWitherName(lombok.core.AnnotationValues, CharSequence, boolean)}. + * Convenient wrapper around {@link TransformationsUtil#toWithName(lombok.core.AnnotationValues, CharSequence, boolean)}. */ - public static String toWitherName(JavacNode field) { - return HandlerUtil.toWitherName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); + public static String toWithName(JavacNode field) { + return HandlerUtil.toWithName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } /** @@ -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('.'); @@ -1877,7 +1883,7 @@ public class JavacHandlerUtil { return (JCExpression) in; } - private static final Pattern SECTION_FINDER = Pattern.compile("^\\s*\\**\\s*[-*][-*]+\\s*([GS]ETTER|WITHER)\\s*[-*][-*]+\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + private static final Pattern SECTION_FINDER = Pattern.compile("^\\s*\\**\\s*[-*][-*]+\\s*([GS]ETTER|WITH(?:ER)?)\\s*[-*][-*]+\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); public static String stripLinesWithTagFromJavadoc(String javadoc, String regexpFragment) { Pattern p = Pattern.compile("^\\s*\\**\\s*" + regexpFragment + "\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); @@ -1892,12 +1898,18 @@ public class JavacHandlerUtil { return javadoc.substring(0, m.start()); } - public static String getJavadocSection(String javadoc, String sectionName) { + public static String getJavadocSection(String javadoc, String sectionNameSpec) { + String[] sectionNames = sectionNameSpec.split("\\|"); Matcher m = SECTION_FINDER.matcher(javadoc); int sectionStart = -1; int sectionEnd = -1; while (m.find()) { - if (m.group(1).equalsIgnoreCase(sectionName)) { + boolean found = false; + for (String sectionName : sectionNames) if (m.group(1).equalsIgnoreCase(sectionName)) { + found = true; + break; + } + if (found) { sectionStart = m.end() + 1; } else if (sectionStart != -1) { sectionEnd = m.start(); @@ -1947,9 +1959,9 @@ public class JavacHandlerUtil { return applySetter(cu, node, "SETTER"); } }, - WITHER { + WITH { @Override public String apply(final JCCompilationUnit cu, final JavacNode node) { - return applySetter(cu, node, "WITHER"); + return applySetter(cu, node, "WITH|WITHER"); } }; 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.<JCAnnotation>of(maker.Annotation(genJavaLangTypeRef(node, "Deprecated"), List.<JCExpression>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.<JCExpression>nil()) : null; + JCAnnotation rrAnn = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(node, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()) : null; + + List<JCAnnotation> annsOnMethod = (deprecateAnn != null && rrAnn != null) ? List.of(deprecateAnn, rrAnn) : deprecateAnn != null ? List.of(deprecateAnn) : rrAnn != null ? List.of(rrAnn) : List.<JCAnnotation>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<JCStatement> statements, Name methodName, List<JCVariableDecl> jcVariableDecls, AccessLevel access) { + private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer<JCStatement> statements, Name methodName, List<JCVariableDecl> 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<JCTypeParameter> typeParams = List.nil(); List<JCExpression> 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<JCStatement> statements = new ListBuffer<JCStatement>(); statements.add(clearStatement); Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); - finishAndInjectMethod(maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.<JCVariableDecl>nil(), access); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.<JCVariableDecl>nil(), access); } protected abstract JCStatement generateClearStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType); - private void generateSingularMethod(boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent, AccessLevel access) { + private void generateSingularMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent, AccessLevel access) { ListBuffer<JCStatement> statements = generateSingularMethodStatements(maker, data, builderType, source); List<JCVariableDecl> params = generateSingularMethodParameters(maker, data, builderType, source); Name name = data.getSingularName(); if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName(getAddMethodName(), name.toString())); statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source)); - finishAndInjectMethod(maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, access); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, access); } protected JCVariableDecl generateSingularMethodParameter(int typeIndex, JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, Name name) { @@ -300,7 +304,7 @@ public class JavacSingularsRecipes { protected abstract List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source); - private void generatePluralMethod(boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent, AccessLevel access) { + private void generatePluralMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent, AccessLevel access) { ListBuffer<JCStatement> statements = generatePluralMethodStatements(maker, data, builderType, source); Name name = data.getPluralName(); if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName(getAddMethodName() + "All", name.toString())); @@ -309,7 +313,7 @@ public class JavacSingularsRecipes { long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); JCVariableDecl param = maker.VarDef(maker.Modifiers(paramFlags), data.getPluralName(), paramType, null); statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source)); - finishAndInjectMethod(maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), access); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), access); } protected ListBuffer<JCStatement> generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java index 5b022206..546dc66e 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -29,6 +29,7 @@ import java.util.Collections; import lombok.AccessLevel; import lombok.core.GuavaTypeMap; import lombok.core.LombokImmutableList; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil; @@ -71,8 +72,8 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField)); } - @Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { - doGenerateMethods(data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); + @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + doGenerateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); } @Override diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java index 9d24f5d5..634a086d 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java @@ -27,6 +27,7 @@ import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.Collections; import lombok.AccessLevel; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil; @@ -66,8 +67,8 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField)); } - @Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { - doGenerateMethods(data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); + @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + doGenerateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); } @Override diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java index 3e498cac..8dc7ecff 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java @@ -28,6 +28,7 @@ import java.util.Arrays; import lombok.AccessLevel; import lombok.core.LombokImmutableList; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil; @@ -97,8 +98,8 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { return Arrays.asList(keyFieldNode, valueFieldNode); } - @Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { - doGenerateMethods(data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); + @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + doGenerateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); } @Override |