diff options
| author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-08-13 15:04:43 +0200 |
|---|---|---|
| committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-08-22 22:42:48 +0200 |
| commit | 15df143df6d35dd64459d717a451a039eb26d761 (patch) | |
| tree | 70fc0be372fd02491f9c5e9d7d68ffe7901da6d8 /src/core/lombok/eclipse/handlers | |
| parent | ff1c01d9e9e66d898c30939b497490b04fe6163c (diff) | |
| download | lombok-15df143df6d35dd64459d717a451a039eb26d761.tar.gz lombok-15df143df6d35dd64459d717a451a039eb26d761.tar.bz2 lombok-15df143df6d35dd64459d717a451a039eb26d761.zip | |
[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.
Diffstat (limited to 'src/core/lombok/eclipse/handlers')
13 files changed, 284 insertions, 110 deletions
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 11a2b9bd..782c6a29 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -111,6 +111,7 @@ import lombok.core.AnnotationValues; import lombok.core.AnnotationValues.AnnotationValue; 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.debug.ProblemReporter; @@ -184,6 +185,23 @@ public class EclipseHandlerUtil { return ma; } + public static MarkerAnnotation generateNamedAnnotation(ASTNode source, String typeName) { + char[][] cc = fromQualifiedName(typeName); + QualifiedTypeReference qtr = new QualifiedTypeReference(cc, poss(source, cc.length)); + setGeneratedBy(qtr, source); + MarkerAnnotation ma = new MarkerAnnotation(qtr, source.sourceStart); + // No matter what value you input for sourceEnd, the AST->DOM converter of eclipse will reparse to find the end, and will fail as + // it can't find code that isn't really there. This results in the end position being set to 2 or 0 or some weird magic value, and thus, + // length, as calculated by end-start, is all screwed up, resulting in IllegalArgumentException during a setSourceRange call MUCH later in the process. + // We solve it by going with a voodoo magic source start value such that the calculated length so happens to exactly be 0. 0 lengths are accepted + // by eclipse. For some reason. + // TL;DR: Don't change 1. 1 is sacred. Trust the 1. + // issue: #408. + ma.sourceStart = 1; + setGeneratedBy(ma, source); + return ma; + } + public static boolean isFieldDeprecated(EclipseNode fieldNode) { if (!(fieldNode.get() instanceof FieldDeclaration)) return false; FieldDeclaration field = (FieldDeclaration) fieldNode.get(); @@ -199,6 +217,11 @@ public class EclipseHandlerUtil { return false; } + public static CheckerFrameworkVersion getCheckerFrameworkVersion(EclipseNode node) { + CheckerFrameworkVersion cfv = node.getAst().readConfiguration(ConfigurationKeys.CHECKER_FRAMEWORK); + return cfv != null ? cfv : CheckerFrameworkVersion.NONE; + } + /** * Checks if the given TypeReference node is likely to be a reference to the provided class. * @@ -1908,11 +1931,13 @@ public class EclipseHandlerUtil { * Create an annotation of the given name, and is marked as being generated by the given source. */ public static MarkerAnnotation makeMarkerAnnotation(char[][] name, ASTNode source) { - long pos = (long)source.sourceStart << 32 | source.sourceEnd; - TypeReference typeRef = new QualifiedTypeReference(name, new long[] {pos, pos, pos}); + long pos = (long) source.sourceStart << 32 | source.sourceEnd; + long[] poss = new long[name.length]; + Arrays.fill(poss, pos); + TypeReference typeRef = new QualifiedTypeReference(name, poss); setGeneratedBy(typeRef, source); - MarkerAnnotation ann = new MarkerAnnotation(typeRef, (int)(pos >> 32)); - ann.declarationSourceEnd = ann.sourceEnd = ann.statementEnd = (int)pos; + MarkerAnnotation ann = new MarkerAnnotation(typeRef, (int) (pos >> 32)); + ann.declarationSourceEnd = ann.sourceEnd = ann.statementEnd = (int) pos; setGeneratedBy(ann, source); return ann; } diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index a8a780d6..da0bf471 100755 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -33,6 +33,7 @@ import java.util.Map; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; @@ -62,6 +63,7 @@ import lombok.AccessLevel; import lombok.core.LombokImmutableList; import lombok.core.SpiLoadUtil; import lombok.core.TypeLibrary; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.eclipse.EclipseNode; public class EclipseSingularsRecipes { @@ -235,7 +237,7 @@ public class EclipseSingularsRecipes { * If you need more control over the return type and value, use * {@link #generateMethods(SingularData, boolean, EclipseNode, boolean, TypeReferenceMaker, StatementMaker)}. */ - public void generateMethods(SingularData data, boolean deprecate, final EclipseNode builderType, boolean fluent, final boolean chain, AccessLevel access) { + public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, final EclipseNode builderType, boolean fluent, final boolean chain, AccessLevel access) { TypeReferenceMaker returnTypeMaker = new TypeReferenceMaker() { @Override public TypeReference make() { return chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); @@ -248,14 +250,14 @@ public class EclipseSingularsRecipes { } }; - generateMethods(data, deprecate, builderType, fluent, returnTypeMaker, returnStatementMaker, access); + generateMethods(cfv, data, deprecate, builderType, 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, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access); + public abstract void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access); public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable); @@ -272,6 +274,15 @@ public class EclipseSingularsRecipes { // -- Utility methods -- + protected Annotation[] generateSelfReturnAnnotations(boolean deprecate, CheckerFrameworkVersion cfv, ASTNode source) { + Annotation deprecated = deprecate ? generateDeprecatedAnnotation(source) : null; + Annotation returnsReceiver = cfv.generateReturnsReceiver() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null; + if (deprecated == null && returnsReceiver == null) return null; + if (deprecated == null) return new Annotation[] {returnsReceiver}; + if (returnsReceiver == null) return new Annotation[] {deprecated}; + return new Annotation[] {deprecated, returnsReceiver}; + } + /** * Adds the requested number of type arguments to the provided type, copying each argument in {@code typeArgs}. If typeArgs is too long, the extra elements are ignored. * If {@code typeArgs} is null or too short, {@code java.lang.Object} will be substituted for each missing type argument. diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index d2b1b823..8bfdeb65 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -37,6 +37,7 @@ import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; @@ -57,9 +58,11 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; +import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TrueLiteral; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; @@ -84,6 +87,7 @@ import lombok.core.handlers.HandlerUtil; import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; @@ -155,7 +159,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { @Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder"); - + CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); + long p = (long) ast.sourceStart << 32 | ast.sourceEnd; Builder builderInstance = annotation.getInstance(); @@ -487,14 +492,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } for (BuilderFieldData bfd : builderFields) { - makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode); + makeSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode); } { MemberExistsResult methodExists = methodExists(buildMethodName, builderType, -1); if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(buildMethodName, builderType, 0); if (methodExists == MemberExistsResult.NOT_EXISTS) { - MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast, accessForInners); + MethodDeclaration md = generateBuildMethod(cfv, tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast, accessForInners); if (md != null) injectMethod(builderType, md); } } @@ -517,7 +522,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { - MethodDeclaration md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast, accessForOuters); + MethodDeclaration md = generateBuilderMethod(cfv, isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast, accessForOuters); if (md != null) injectMethod(tdParent, md); } @@ -534,7 +539,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { tps[i].name = typeArgsForToBuilder.get(i); } } - MethodDeclaration md = generateToBuilderMethod(toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast, accessForOuters); + MethodDeclaration md = generateToBuilderMethod(cfv, toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast, accessForOuters); if (md != null) injectMethod(tdParent, md); } @@ -547,7 +552,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } private static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'}; - private MethodDeclaration generateToBuilderMethod(String methodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, boolean fluent, ASTNode source, AccessLevel access) { + private MethodDeclaration generateToBuilderMethod(CheckerFrameworkVersion cfv, String methodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, boolean fluent, ASTNode source, AccessLevel access) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; @@ -623,6 +628,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { out.statements = new Statement[] {new ReturnStatement(receiver, pS, pE)}; } + if (cfv.generateUnique()) { + out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } + out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); return out; @@ -650,7 +659,35 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return decl; } - public MethodDeclaration generateBuildMethod(EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source, AccessLevel access) { + static Argument[] generateBuildArgs(CheckerFrameworkVersion cfv, EclipseNode type, List<BuilderFieldData> builderFields, ASTNode source) { + if (!cfv.generateCalledMethods()) return null; + + List<char[]> mandatories = new ArrayList<char[]>(); + for (BuilderFieldData bfd : builderFields) { + if (bfd.singularData == null && bfd.nameOfSetFlag == null) mandatories.add(bfd.name); + } + + if (mandatories.size() == 0) return null; + char[][] nameCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__CALLED); + SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameCalled, poss(source, nameCalled.length)), source.sourceStart); + if (mandatories.size() == 1) { + ann.memberValue = new StringLiteral(mandatories.get(0), 0, 0, 0); + } else { + ArrayInitializer arr = new ArrayInitializer(); + arr.sourceStart = source.sourceStart; + arr.sourceEnd = source.sourceEnd; + arr.expressions = new Expression[mandatories.size()]; + for (int i = 0; i < arr.expressions.length; i++) { + arr.expressions[i] = new StringLiteral(mandatories.get(i), source.sourceStart, source.sourceEnd, 0); + } + ann.memberValue = arr; + } + Argument arg = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, new SingleTypeReference(type.getName().toCharArray(), source.sourceStart), Modifier.FINAL); + arg.annotations = new Annotation[] {ann}; + return new Argument[] {arg}; + } + + public MethodDeclaration generateBuildMethod(CheckerFrameworkVersion cfv, EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source, AccessLevel access) { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; List<Statement> statements = new ArrayList<Statement>(); @@ -723,6 +760,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); + if (cfv.generateSideEffectFree()) { + out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; + } + out.arguments = generateBuildArgs(cfv, type, builderFields, source); out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } @@ -754,7 +795,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return out; } - public MethodDeclaration generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source, AccessLevel access) { + public MethodDeclaration generateBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source, AccessLevel access) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; @@ -768,7 +809,15 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { AllocationExpression invoke = new AllocationExpression(); invoke.type = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p); out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)}; - + Annotation uniqueAnn = cfv.generateUnique() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) : null; + Annotation sefAnn = cfv.generateSideEffectFree() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) : null; + if (uniqueAnn != null && sefAnn != null) { + out.annotations = new Annotation[] {uniqueAnn, sefAnn}; + } else if (uniqueAnn != null) { + out.annotations = new Annotation[] {uniqueAnn}; + } else if (sefAnn != null) { + out.annotations = new Annotation[] {sefAnn}; + } out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); return out; } @@ -813,18 +862,19 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { private static final AbstractMethodDeclaration[] EMPTY = {}; - public void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode) { + public void makeSetterMethodsForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode) { boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - makeSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode); + makeSimpleSetterMethodForBuilder(cfv, builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode); } else { - bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, fluent, chain, access); + bfd.singularData.getSingularizer().generateMethods(cfv, bfd.singularData, deprecate, builderType, fluent, chain, access); } } - private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode) { + private void makeSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode) { TypeDeclaration td = (TypeDeclaration) builderType.get(); AbstractMethodDeclaration[] existing = td.methods; + ASTNode source = sourceNode.get(); if (existing == null) existing = EMPTY; int len = existing.length; FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); @@ -838,11 +888,20 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { String setterName = fluent ? new String(paramName) : HandlerUtil.buildAccessorName("set", new String(paramName)); - List<Annotation> methodAnnsList = Collections.<Annotation>emptyList(); - Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); - if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns); + List<Annotation> methodAnnsList = Arrays.asList(EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode)); MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, chain, toEclipseModifier(access), - sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList()); + sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(source, annotations)) : Collections.<Annotation>emptyList()); + if (cfv.generateCalledMethods()) { + Argument[] arr = setter.arguments == null ? new Argument[0] : setter.arguments; + Argument[] newArr = new Argument[arr.length + 1]; + System.arraycopy(arr, 0, newArr, 1, arr.length); + newArr[0] = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, new SingleTypeReference(builderType.getName().toCharArray(), 0), Modifier.FINAL); + char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED); + SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart); + ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0); + newArr[0].annotations = new Annotation[] {ann}; + setter.arguments = newArr; + } injectMethod(builderType, setter); } diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index c6b51042..8f981c1a 100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/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 @@ -39,6 +39,7 @@ import lombok.ConfigurationKeys; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.core.AST.Kind; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; @@ -456,14 +457,14 @@ public class HandleConstructor { constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]); /* Generate annotations that must be put on the generated method, and attach them. */ { - Annotation[] constructorProperties = null; - if (addConstructorProperties && !isLocalType(type)) { - constructorProperties = createConstructorProperties(source, fieldsToParam); - } + Annotation[] constructorProperties = null, checkerFramework = null; + if (addConstructorProperties && !isLocalType(type)) constructorProperties = createConstructorProperties(source, fieldsToParam); + if (getCheckerFrameworkVersion(type).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) }; constructor.annotations = copyAnnotations(source, onConstructor.toArray(new Annotation[0]), - constructorProperties); + constructorProperties, + checkerFramework); } constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); @@ -551,7 +552,9 @@ public class HandleConstructor { assigns.add(nameRef); Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); - parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode)); + Annotation[] checkerFramework = null; + if (getCheckerFrameworkVersion(fieldNode).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) }; + parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode), checkerFramework); params.add(parameter); } diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 046b197f..1bca4767 100755 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/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 @@ -42,6 +42,7 @@ import lombok.core.handlers.InclusionExclusionUtils; import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; import lombok.core.configuration.CallSuperType; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; @@ -235,7 +236,12 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH method.modifiers = toEclipseModifier(AccessLevel.PUBLIC); method.returnType = TypeReference.baseTypeReference(TypeIds.T_int, 0); setGeneratedBy(method.returnType, source); - method.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)}; + Annotation overrideAnnotation = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source); + if (getCheckerFrameworkVersion(type).generateSideEffectFree()) { + method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) }; + } else { + method.annotations = new Annotation[] { overrideAnnotation }; + } method.selector = "hashCode".toCharArray(); method.thrownExceptions = null; method.typeParameters = null; @@ -508,7 +514,12 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); method.returnType.sourceStart = pS; method.returnType.sourceEnd = pE; setGeneratedBy(method.returnType, source); - method.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)}; + Annotation overrideAnnotation = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source); + if (getCheckerFrameworkVersion(type).generateSideEffectFree()) { + method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) }; + } else { + method.annotations = new Annotation[] { overrideAnnotation }; + } method.selector = "equals".toCharArray(); method.thrownExceptions = null; method.typeParameters = null; @@ -785,6 +796,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH setGeneratedBy(returnStatement, source); method.statements = new Statement[] {returnStatement}; + if (getCheckerFrameworkVersion(type).generateSideEffectFree()) method.annotations = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) }; return method; } diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 7d3fe62f..7ba84cdc 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 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 @@ -38,6 +38,7 @@ import lombok.experimental.Delegate; import lombok.Getter; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.agent.PatchDelegate; @@ -262,16 +263,16 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { EclipseHandlerUtil.registerCreatedLazyGetter((FieldDeclaration) fieldNode.get(), method.selector, returnType); - /* Generate annotations that must be put on the generated method, and attach them. */ { - Annotation[] deprecated = null; - if (isFieldDeprecated(fieldNode)) { - deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; - } + /* Generate annotations that must be put on the generated method, and attach them. */ { + Annotation[] deprecated = null, checkerFramework = null; + if (isFieldDeprecated(fieldNode)) deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; + if (getCheckerFrameworkVersion(fieldNode).generateSideEffectFree()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) }; method.annotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), findCopyableAnnotations(fieldNode), findDelegatesAndMarkAsHandled(fieldNode), + checkerFramework, deprecated); } diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index bb704ead..bfa60db0 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -36,6 +36,7 @@ import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.Setter; import lombok.core.AST.Kind; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; @@ -200,7 +201,11 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { returnThis = new ReturnStatement(thisRef, pS, pE); } - return createSetter(parent, deprecate, fieldNode, name, paramName, booleanFieldToSet, returnType, returnThis, modifier, sourceNode, onMethod, onParam); + MethodDeclaration d = createSetter(parent, deprecate, fieldNode, name, paramName, booleanFieldToSet, returnType, returnThis, modifier, sourceNode, onMethod, onParam); + if (shouldReturnThis && getCheckerFrameworkVersion(sourceNode).generateReturnsReceiver()) { + d.annotations = copyAnnotations(source, d.annotations, new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) }); + } + return d; } static MethodDeclaration createSetter(TypeDeclaration parent, boolean deprecate, EclipseNode fieldNode, String name, char[] paramName, char[] booleanFieldToSet, TypeReference returnType, Statement returnStatement, int modifier, EclipseNode sourceNode, List<Annotation> onMethod, List<Annotation> onParam) { diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 88479911..8f0ef338 100755 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -57,9 +57,11 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; +import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.SuperReference; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; @@ -81,6 +83,7 @@ import lombok.ConfigurationKeys; import lombok.Singular; import lombok.ToString; import lombok.core.AST.Kind; +import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.handlers.HandlerUtil; import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; @@ -119,6 +122,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { @Override public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); + CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); long p = (long) ast.sourceStart << 32 | ast.sourceEnd; @@ -269,7 +273,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // If there is no superclass, superclassBuilderClassExpression is still == null at this point. // You can use it to check whether to inherit or not. - generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, + generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, superclassBuilderClass != null); // Create the abstract builder class, or reuse an existing one. @@ -334,12 +338,12 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Generate abstract self() and build() methods in the abstract builder. - injectMethod(builderType, generateAbstractSelfMethod(tdParent, superclassBuilderClass != null, builderGenericName)); - injectMethod(builderType, generateAbstractBuildMethod(tdParent, buildMethodName, superclassBuilderClass != null, classGenericName, ast)); + injectMethod(builderType, generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClass != null, builderGenericName)); + injectMethod(builderType, generateAbstractBuildMethod(cfv, builderType, buildMethodName, builderFields, superclassBuilderClass != null, classGenericName, ast)); // 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. @@ -386,22 +390,22 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { annotationNode.addWarning("Not generating toBuilder() as it already exists."); break; case NOT_EXISTS: - injectMethod(tdParent, generateToBuilderMethod(builderClassName, builderImplClassName, tdParent, typeParams, ast)); + injectMethod(tdParent, generateToBuilderMethod(cfv, builderClassName, builderImplClassName, tdParent, typeParams, ast)); default: // Should not happen. } } // Create the self() and build() methods in the BuilderImpl. - injectMethod(builderImplType, generateSelfMethod(builderImplType, typeParams, p)); + injectMethod(builderImplType, generateSelfMethod(cfv, builderImplType, typeParams, p)); if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { - injectMethod(builderImplType, generateBuildMethod(tdParent, buildMethodName, returnType, ast)); + injectMethod(builderImplType, generateBuildMethod(cfv, builderImplType, buildMethodName, returnType, builderFields, ast)); } // Add the builder() method to the annotated cla |
