From e95680a76733c22ee5937a586ee50c703d5ba621 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 20 Jan 2020 15:25:08 +0100 Subject: [issue #2221] [issue #788] Lombok now adds nullity annotations. Which 'flavour' is defined in lombok.config; applied to toString, equals, canEqual, and plural-form of `@Singular`. --- .../javac/handlers/HandleEqualsAndHashCode.java | 21 ++--- src/core/lombok/javac/handlers/HandleToString.java | 8 +- src/core/lombok/javac/handlers/HandleWith.java | 3 +- .../lombok/javac/handlers/JavacHandlerUtil.java | 99 ++++++++++++++++++++++ .../javac/handlers/JavacSingularsRecipes.java | 22 +++-- .../handlers/singulars/JavacGuavaSingularizer.java | 11 +-- 6 files changed, 130 insertions(+), 34 deletions(-) (limited to 'src/core/lombok/javac/handlers') diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index 0d0369b9..c4cf28da 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -383,18 +383,6 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler annsOnParamOnMethod = List.nil(); - String nearest = scanForNearestAnnotation(typeNode, "org.eclipse.jdt.annotation.NonNullByDefault"); - if (nearest != null) { - JCAnnotation m = maker.Annotation(genTypeRef(typeNode, "org.eclipse.jdt.annotation.Nullable"), List.nil()); - annsOnParamOnMethod = annsOnParamOnMethod.prepend(m); - } - - nearest = scanForNearestAnnotation(typeNode, "javax.annotation.ParametersAreNullableByDefault", "javax.annotation.ParametersAreNonnullByDefault"); - if ("javax.annotation.ParametersAreNonnullByDefault".equals(nearest)) { - JCAnnotation m = maker.Annotation(genTypeRef(typeNode, "javax.annotation.Nullable"), List.nil()); - annsOnParamOnMethod = annsOnParamOnMethod.prepend(m); - } - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.nil()); List annsOnMethod = List.of(overrideAnnotation); CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); @@ -415,7 +403,10 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler statements = new ListBuffer(); - final List params = List.of(maker.VarDef(maker.Modifiers(finalFlag | Flags.PARAMETER, onParam), oName, objectType, null)); + JCVariableDecl param = maker.VarDef(maker.Modifiers(finalFlag | Flags.PARAMETER, onParam), oName, objectType, null); + JavacHandlerUtil.createRelevantNullableAnnotation(typeNode, param); + + final List params = List.of(param); /* if (o == this) return true; */ { statements.append(maker.If(maker.Binary(CTC_EQUAL, maker.Ident(oName), @@ -538,7 +529,9 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler params = List.of(maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null)); + JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null); + createRelevantNullableAnnotation(typeNode, param); + List params = List.of(param); JCBlock body = maker.Block(0, List.of( maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false))))); diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index d0d36e06..0a950f7c 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2019 The Project Lombok Authors. + * Copyright (C) 2009-2020 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 @@ -253,8 +253,10 @@ public class HandleToString extends JavacAnnotationHandler { JCBlock body = maker.Block(0, List.of(returnStatement)); - return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("toString"), returnType, - List.nil(), List.nil(), List.nil(), body, null), source, typeNode.getContext()); + JCMethodDecl methodDef = maker.MethodDef(mods, typeNode.toName("toString"), returnType, + List.nil(), List.nil(), List.nil(), body, null); + createRelevantNonNullAnnotation(typeNode, methodDef); + return recursiveSetGeneratedBy(methodDef, source, typeNode.getContext()); } public static String getTypeName(JavacNode typeNode) { diff --git a/src/core/lombok/javac/handlers/HandleWith.java b/src/core/lombok/javac/handlers/HandleWith.java index 7b2417da..6977b10e 100644 --- a/src/core/lombok/javac/handlers/HandleWith.java +++ b/src/core/lombok/javac/handlers/HandleWith.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2019 The Project Lombok Authors. + * Copyright (C) 2012-2020 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 @@ -211,6 +211,7 @@ public class HandleWith extends JavacAnnotationHandler { long access = toJavacModifier(level); JCMethodDecl createdWith = createWith(access, fieldNode, fieldNode.getTreeMaker(), source, onMethod, onParam, makeAbstract); + createRelevantNonNullAnnotation(fieldNode, createdWith); ClassSymbol sym = ((JCClassDecl) fieldNode.up().get()).sym; Type returnType = sym == null ? null : sym.type; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 9359b1ae..0ef8c359 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -94,6 +94,7 @@ import lombok.core.CleanupTask; import lombok.core.LombokImmutableList; import lombok.core.TypeResolver; import lombok.core.configuration.CheckerFrameworkVersion; +import lombok.core.configuration.NullAnnotationLibrary; import lombok.core.configuration.NullCheckExceptionType; import lombok.core.configuration.TypeName; import lombok.core.handlers.HandlerUtil; @@ -1085,6 +1086,13 @@ public class JavacHandlerUtil { } } + static void setAnnotations(JCTree obj, List anns) { + init(obj.getClass()); + try { + ANNOTATIONS.set(obj, anns); + } catch (Exception e) {} + } + static JCExpression getUnderlyingType(JCTree obj) { init(obj.getClass()); try { @@ -2054,4 +2062,95 @@ public class JavacHandlerUtil { String p = extending.toString(); return p.equals("Object") || p.equals("java.lang.Object"); } + + public static void createRelevantNullableAnnotation(JavacNode typeNode, JCMethodDecl mth) { + NullAnnotationLibrary lib = typeNode.getAst().readConfiguration(ConfigurationKeys.ADD_NULL_ANNOTATIONS); + if (lib == null) return; + applyAnnotationToMethodDecl(typeNode, mth, lib.getNullableAnnotation(), lib.isTypeUse()); + } + + public static void createRelevantNonNullAnnotation(JavacNode typeNode, JCMethodDecl mth) { + NullAnnotationLibrary lib = typeNode.getAst().readConfiguration(ConfigurationKeys.ADD_NULL_ANNOTATIONS); + if (lib == null) return; + applyAnnotationToMethodDecl(typeNode, mth, lib.getNonNullAnnotation(), lib.isTypeUse()); + } + + public static void createRelevantNonNullAnnotation(JavacNode typeNode, JCVariableDecl arg) { + NullAnnotationLibrary lib = typeNode.getAst().readConfiguration(ConfigurationKeys.ADD_NULL_ANNOTATIONS); + if (lib == null) return; + + applyAnnotationToVarDecl(typeNode, arg, lib.getNonNullAnnotation(), lib.isTypeUse()); + } + + public static void createRelevantNullableAnnotation(JavacNode typeNode, JCVariableDecl arg) { + NullAnnotationLibrary lib = typeNode.getAst().readConfiguration(ConfigurationKeys.ADD_NULL_ANNOTATIONS); + if (lib == null) return; + + applyAnnotationToVarDecl(typeNode, arg, lib.getNullableAnnotation(), lib.isTypeUse()); + } + + private static void applyAnnotationToMethodDecl(JavacNode typeNode, JCMethodDecl mth, String annType, boolean typeUse) { + if (annType == null) return; + JavacTreeMaker maker = typeNode.getTreeMaker(); + + JCAnnotation m = maker.Annotation(genTypeRef(typeNode, annType), List.nil()); + if (typeUse) { + JCExpression resType = mth.restype; + if (resType instanceof JCTypeApply) { + JCTypeApply ta = (JCTypeApply) resType; + resType = ta.clazz; + } + + if (resType instanceof JCFieldAccess || resType instanceof JCArrayTypeTree) { + mth.restype = maker.AnnotatedType(List.of(m), resType); + return; + } + + if (JCAnnotatedTypeReflect.is(resType)) { + List annotations = JCAnnotatedTypeReflect.getAnnotations(resType); + JCAnnotatedTypeReflect.setAnnotations(resType, annotations.prepend(m)); + return; + } + + if (resType instanceof JCPrimitiveTypeTree || resType instanceof JCIdent) { + mth.mods.annotations = mth.mods.annotations == null ? List.of(m) : mth.mods.annotations.prepend(m); + } + } else { + mth.mods.annotations = mth.mods.annotations == null ? List.of(m) : mth.mods.annotations.prepend(m); + } + } + + private static void applyAnnotationToVarDecl(JavacNode typeNode, JCVariableDecl arg, String annType, boolean typeUse) { + if (annType == null) return; + JavacTreeMaker maker = typeNode.getTreeMaker(); + + JCAnnotation m = maker.Annotation(genTypeRef(typeNode, annType), List.nil()); + if (typeUse) { + JCExpression varType = arg.vartype; + JCTypeApply ta = null; + if (varType instanceof JCTypeApply) { + ta = (JCTypeApply) varType; + varType = ta.clazz; + } + + if (varType instanceof JCFieldAccess || varType instanceof JCArrayTypeTree) { + varType = maker.AnnotatedType(List.of(m), varType); + if (ta != null) ta.clazz = varType; + else arg.vartype = varType; + return; + } + + if (JCAnnotatedTypeReflect.is(varType)) { + List annotations = JCAnnotatedTypeReflect.getAnnotations(varType); + JCAnnotatedTypeReflect.setAnnotations(varType, annotations.prepend(m)); + return; + } + + if (varType instanceof JCPrimitiveTypeTree || varType instanceof JCIdent) { + arg.mods.annotations = arg.mods.annotations == null ? List.of(m) : arg.mods.annotations.prepend(m); + } + } else { + arg.mods.annotations = arg.mods.annotations == null ? List.of(m) : arg.mods.annotations.prepend(m); + } + } } diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index a5d4a295..9dab3da5 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -273,12 +273,19 @@ public class JavacSingularsRecipes { generateClearMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, access); } - private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, AccessLevel access) { + private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, AccessLevel access, NullCollectionBehavior nullBehavior) { if (returnStatement != null) statements.append(returnStatement); JCBlock body = maker.Block(0, statements.toList()); JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access); List typeParams = List.nil(); List thrown = List.nil(); + + if (nullBehavior == NullCollectionBehavior.IGNORE) { + for (JCVariableDecl d : jcVariableDecls) createRelevantNullableAnnotation(builderType, d); + } else if (nullBehavior != null) { + for (JCVariableDecl d : jcVariableDecls) createRelevantNonNullAnnotation(builderType, d); + } + JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, jcVariableDecls, thrown, body, null); recursiveSetGeneratedBy(method, source, builderType.getContext()); injectMethod(builderType, method); @@ -290,7 +297,7 @@ public class JavacSingularsRecipes { statements.add(clearStatement); Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); - finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.nil(), access); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.nil(), access, null); } protected abstract JCStatement generateClearStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType); @@ -304,7 +311,7 @@ public class JavacSingularsRecipes { if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(setterPrefix, name.toString())); statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source)); - finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, access); + finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, access, null); } protected JCVariableDecl generateSingularMethodParameter(int typeIndex, JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, Name name) { @@ -336,10 +343,11 @@ public class JavacSingularsRecipes { JCExpression paramType = getPluralMethodParamType(builderType); paramType = addTypeArgs(getTypeArgumentsCount(), true, builderType, paramType, data.getTypeArgs(), source); 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)); - NullCollectionBehavior behavior = data.getNullCollectionBehavior(); + if (behavior == null) behavior = NullCollectionBehavior.IGNORE; + JCModifiers paramMods = maker.Modifiers(paramFlags); + JCVariableDecl param = maker.VarDef(paramMods, data.getPluralName(), paramType, null); + statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source)); if (behavior == NullCollectionBehavior.IGNORE) { JCExpression incomingIsNotNull = maker.Binary(CTC_NOT_EQUAL, maker.Ident(data.getPluralName()), maker.Literal(CTC_BOT, null)); @@ -361,7 +369,7 @@ public class JavacSingularsRecipes { } } - finishAndInjectMethod(cfv, 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, behavior); } protected ListBuffer 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 546dc66e..7cd676c0 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 The Project Lombok Authors. + * Copyright (C) 2015-2020 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 @@ -121,14 +121,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { @Override protected JCExpression getPluralMethodParamType(JavacNode builderType) { - JCExpression paramType; - String aaTypeName = getAddAllTypeName(); - if (aaTypeName.startsWith("java.lang.") && aaTypeName.indexOf('.', 11) == -1) { - paramType = genJavaLangTypeRef(builderType, aaTypeName.substring(10)); - } else { - paramType = chainDotsString(builderType, aaTypeName); - } - return paramType; + return genTypeRef(builderType, getAddAllTypeName()); } @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer statements, Name targetVariableName, String builderVariable) { -- cgit