diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/lombok/Builder.java | 4 | ||||
-rw-r--r-- | src/core/lombok/ConfigurationKeys.java | 7 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java | 12 | ||||
-rwxr-xr-x | src/core/lombok/eclipse/handlers/HandleBuilder.java | 16 | ||||
-rwxr-xr-x | src/core/lombok/eclipse/handlers/HandleSuperBuilder.java | 6 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacResolution.java | 6 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleBuilder.java | 34 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java | 41 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleSuperBuilder.java | 10 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/PrettyPrinter.java | 3 | ||||
-rw-r--r-- | src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java | 21 | ||||
-rw-r--r-- | src/eclipseAgent/lombok/eclipse/agent/PatchVal.java | 126 | ||||
-rwxr-xr-x | src/eclipseAgent/lombok/launch/PatchFixesHider.java | 12 |
13 files changed, 251 insertions, 47 deletions
diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index a60af9ee..dfa5ecb5 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -129,9 +129,9 @@ public @interface Builder { /** * Name of the builder class. * - * Default for {@code @Builder} on types and constructors: {@code (TypeName)Builder}. + * Default for {@code @Builder} on types and constructors: see the configkey {@code lombok.builder.className}, which if not set defaults to {@code (TypeName)Builder}. * <p> - * Default for {@code @Builder} on methods: {@code (ReturnTypeName)Builder}. + * Default for {@code @Builder} on methods: see the configkey {@code lombok.builder.className}, which if not set defaults to {@code (ReturnTypeName)Builder}. * * @return Name of the builder class that will be generated (or if it already exists, will be filled with builder elements). */ diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index ecfddb2a..dda0b54b 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -258,6 +258,13 @@ public class ConfigurationKeys { // ----- Builder ----- /** + * lombok configuration: {@code lombok.builder.classNames} = <String: aJavaIdentifier (optionally with a star as placeholder for the type name)> (Default: {@code *Builder}). + * + * For any usage of the {@code @Builder} annotation without an explicit {@code builderClassName} parameter, this value is used to determine the name of the builder class to generate (or to adapt if such an inner class already exists). + */ + public static final ConfigurationKey<String> BUILDER_CLASS_NAME = new ConfigurationKey<String>("lombok.builder.className", "Default name of the generated builder class. A * is replaced with the name of the relevant type (default = *Builder).") {}; + + /** * lombok configuration: {@code lombok.builder.flagUsage} = {@code WARNING} | {@code ERROR}. * * If set, <em>any</em> usage of {@code @Builder} results in a warning / error. diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index f04c541f..1a0633bf 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -114,6 +114,7 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; @@ -844,7 +845,6 @@ public class EclipseHandlerUtil { } public static TypeReference makeType(TypeBinding binding, ASTNode pos, boolean allowCompound) { - if (binding.getClass() == EclipseReflectiveMembers.INTERSECTION_BINDING) { Object[] arr = (Object[]) EclipseReflectiveMembers.reflect(EclipseReflectiveMembers.INTERSECTION_BINDING_TYPES, binding); binding = (TypeBinding) arr[0]; @@ -933,7 +933,12 @@ public class EclipseHandlerUtil { WildcardBinding wildcard = (WildcardBinding) binding; if (wildcard.boundKind == Wildcard.EXTENDS) { if (!allowCompound) { - return makeType(wildcard.bound, pos, false); + TypeBinding bound = wildcard.bound; + boolean isObject = bound.id == TypeIds.T_JavaLangObject; + TypeBinding[] otherBounds = wildcard.otherBounds; + if (isObject && otherBounds != null && otherBounds.length > 0) { + return makeType(otherBounds[0], pos, false); + } else return makeType(bound, pos, false); } else { Wildcard out = new Wildcard(Wildcard.EXTENDS); setGeneratedBy(out, pos); @@ -960,7 +965,8 @@ public class EclipseHandlerUtil { // Finally, add however many nullTypeArgument[] arrays as that are missing, inverse the list, toArray it, and use that as PTR's typeArgument argument. List<TypeReference[]> params = new ArrayList<TypeReference[]>(); - /* Calculate generics */ { + /* Calculate generics */ + if (!(binding instanceof RawTypeBinding)) { TypeBinding b = binding; while (true) { boolean isFinalStop = b.isLocalType() || !b.isMemberType() || b.enclosingType() == null; diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 96431a83..aa9d2147 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -209,6 +209,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { List<EclipseNode> nonFinalNonDefaultedFields = null; + if (builderClassName.isEmpty()) builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); + if (builderClassName == null || builderClassName.isEmpty()) builderClassName = "*Builder"; + boolean replaceNameInBuilderClassName = builderClassName.contains("*"); + if (parent.get() instanceof TypeDeclaration) { tdParent = parent; TypeDeclaration td = (TypeDeclaration) tdParent.get(); @@ -265,7 +269,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { typeParams = td.typeParameters; thrownExceptions = null; nameOfStaticBuilderMethod = null; - if (builderClassName.isEmpty()) builderClassName = new String(td.name) + "Builder"; + if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", new String(td.name)); + replaceNameInBuilderClassName = false; } else if (parent.get() instanceof ConstructorDeclaration) { ConstructorDeclaration cd = (ConstructorDeclaration) parent.get(); if (cd.typeParameters != null && cd.typeParameters.length > 0) { @@ -279,12 +284,13 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { typeParams = td.typeParameters; thrownExceptions = cd.thrownExceptions; nameOfStaticBuilderMethod = null; - if (builderClassName.isEmpty()) builderClassName = new String(cd.selector) + "Builder"; + if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", new String(cd.selector)); + replaceNameInBuilderClassName = false; } else if (parent.get() instanceof MethodDeclaration) { MethodDeclaration md = (MethodDeclaration) parent.get(); tdParent = parent.up(); isStatic = md.isStatic(); - + if (toBuilder) { final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; char[] token; @@ -360,7 +366,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { typeParams = md.typeParameters; thrownExceptions = md.thrownExceptions; nameOfStaticBuilderMethod = md.selector; - if (builderClassName.isEmpty()) { + if (replaceNameInBuilderClassName) { char[] token; if (md.returnType instanceof QualifiedTypeReference) { char[][] tokens = ((QualifiedTypeReference) md.returnType).tokens; @@ -387,7 +393,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { token = newToken; } - builderClassName = new String(token) + "Builder"; + builderClassName = builderClassName.replace("*", new String(token)); } } else { annotationNode.addError("@Builder is only supported on types, constructors, and methods."); diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 9a86d372..f204bc24 100755 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -203,7 +203,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Set the names of the builder classes. - String builderClassName = String.valueOf(td.name) + "Builder"; + String builderClassNameTemplate = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); + if (builderClassNameTemplate == null || builderClassNameTemplate.isEmpty()) builderClassNameTemplate = "*Builder"; + String builderClassName = builderClassNameTemplate.replace("*", String.valueOf(td.name)); String builderImplClassName = builderClassName + "Impl"; typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; @@ -228,7 +230,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { if (extendsClause instanceof QualifiedTypeReference) { QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause; String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken()); - String superclassBuilderClassName = superclassClassName + "Builder"; + String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName); char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); tokens[tokens.length] = superclassBuilderClassName.toCharArray(); diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index abbf6726..7f940d2a 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -336,7 +336,7 @@ public class JavacResolution { if (type instanceof ClassType) { List<Type> ifaces = ((ClassType) type).interfaces_field; Type supertype = ((ClassType) type).supertype_field; - if (ifaces != null && ifaces.length() == 1) { + if (isObject(supertype) && ifaces != null && ifaces.length() > 0) { return typeToJCTree(ifaces.get(0), ast, allowCompound, allowVoid); } if (supertype != null) return typeToJCTree(supertype, ast, allowCompound, allowVoid); @@ -402,6 +402,10 @@ public class JavacResolution { return genericsToJCTreeNodes(generics, ast, replacement); } + private static boolean isObject(Type supertype) { + return supertype.tsym.toString().equals("java.lang.Object"); + } + private static JCExpression genericsToJCTreeNodes(List<Type> generics, JavacAST ast, JCExpression rawTypeNode) throws TypeNotConvertibleException { if (generics != null && !generics.isEmpty()) { ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index d758f602..b339c2ca 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -157,6 +157,10 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { ArrayList<JavacNode> nonFinalNonDefaultedFields = null; + if (builderClassName.isEmpty()) builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); + if (builderClassName == null || builderClassName.isEmpty()) builderClassName = "*Builder"; + boolean replaceNameInBuilderClassName = builderClassName.contains("*"); + if (parent.get() instanceof JCClassDecl) { tdParent = parent; JCClassDecl td = (JCClassDecl) tdParent.get(); @@ -211,7 +215,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { typeParams = td.typarams; thrownExceptions = List.nil(); nameOfBuilderMethod = null; - if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder"; + if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", td.name.toString()); + replaceNameInBuilderClassName = false; } else if (fillParametersFrom != null && fillParametersFrom.getName().toString().equals("<init>")) { JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get(); if (!jmd.typarams.isEmpty()) { @@ -225,7 +230,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { typeParams = td.typarams; thrownExceptions = jmd.thrown; nameOfBuilderMethod = null; - if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder"; + if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", td.name.toString()); + replaceNameInBuilderClassName = false; } else if (fillParametersFrom != null) { tdParent = parent.up(); JCClassDecl td = (JCClassDecl) tdParent.get(); @@ -239,9 +245,10 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { if (returnType instanceof JCTypeApply) { returnType = cloneType(tdParent.getTreeMaker(), returnType, ast, annotationNode.getContext()); } - if (builderClassName.isEmpty()) { + if (replaceNameInBuilderClassName) { + String replStr = null; if (returnType instanceof JCFieldAccess) { - builderClassName = ((JCFieldAccess) returnType).name.toString() + "Builder"; + replStr = ((JCFieldAccess) returnType).name.toString(); } else if (returnType instanceof JCIdent) { Name n = ((JCIdent) returnType).name; @@ -251,27 +258,30 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return; } } - builderClassName = n.toString() + "Builder"; + replStr = n.toString(); } else if (returnType instanceof JCPrimitiveTypeTree) { - builderClassName = returnType.toString() + "Builder"; - if (Character.isLowerCase(builderClassName.charAt(0))) { - builderClassName = Character.toTitleCase(builderClassName.charAt(0)) + builderClassName.substring(1); + replStr = returnType.toString(); + if (Character.isLowerCase(replStr.charAt(0))) { + replStr = Character.toTitleCase(replStr.charAt(0)) + replStr.substring(1); } } else if (returnType instanceof JCTypeApply) { JCExpression clazz = ((JCTypeApply) returnType).clazz; if (clazz instanceof JCFieldAccess) { - builderClassName = ((JCFieldAccess) clazz).name + "Builder"; + replStr = ((JCFieldAccess) clazz).name.toString(); } else if (clazz instanceof JCIdent) { - builderClassName = ((JCIdent) clazz).name + "Builder"; + replStr = ((JCIdent) clazz).name.toString(); } } - if (builderClassName.isEmpty()) { + if (replStr == null || replStr.isEmpty()) { // This shouldn't happen. System.err.println("Lombok bug ID#20140614-1651: javac HandleBuilder: return type to name conversion failed: " + returnType.getClass()); - builderClassName = td.name.toString() + "Builder"; + replStr = td.name.toString(); } + builderClassName = builderClassName.replace("*", replStr); + replaceNameInBuilderClassName = false; } + if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", td.name.toString()); if (toBuilder) { final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; if (returnType instanceof JCArrayTypeTree) { diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index cb12bd4e..e4d7fa7f 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -25,6 +25,7 @@ import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.javac.Javac.*; import static lombok.javac.handlers.JavacHandlerUtil.*; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -234,7 +235,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas for (Included<JavacNode, EqualsAndHashCode.Include> member : members) { JavacNode memberNode = member.getNode(); - JCExpression fType = getFieldType(memberNode, fieldAccess); + JCExpression fType = unnotate(getFieldType(memberNode, fieldAccess)); boolean isMethod = memberNode.getKind() == Kind.METHOD; JCExpression fieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess); @@ -279,9 +280,10 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas break; } } else if (fType instanceof JCArrayTypeTree) { + JCArrayTypeTree array = (JCArrayTypeTree) fType; /* java.util.Arrays.deepHashCode(this.fieldName) //use just hashCode() for primitive arrays. */ - boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree; - boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree; + boolean multiDim = unnotate(array.elemtype) instanceof JCArrayTypeTree; + boolean primitiveArray = unnotate(array.elemtype) instanceof JCPrimitiveTypeTree; boolean useDeepHC = multiDim || !primitiveArray; JCExpression hcMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepHC ? "deepHashCode" : "hashCode"); @@ -430,7 +432,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas JavacNode memberNode = member.getNode(); boolean isMethod = memberNode.getKind() == Kind.METHOD; - JCExpression fType = getFieldType(memberNode, fieldAccess); + JCExpression fType = unnotate(getFieldType(memberNode, fieldAccess)); JCExpression thisFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess); JCExpression otherFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode, maker.Ident(otherName)) : createFieldAccessor(maker, memberNode, fieldAccess, maker.Ident(otherName)); if (fType instanceof JCPrimitiveTypeTree) { @@ -450,9 +452,10 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas break; } } else if (fType instanceof JCArrayTypeTree) { + JCArrayTypeTree array = (JCArrayTypeTree) fType; /* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */ - boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree; - boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree; + boolean multiDim = unnotate(array.elemtype) instanceof JCArrayTypeTree; + boolean primitiveArray = unnotate(array.elemtype) instanceof JCPrimitiveTypeTree; boolean useDeepEquals = multiDim || !primitiveArray; JCExpression eqMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals"); @@ -522,4 +525,30 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas public JCStatement returnBool(JavacTreeMaker maker, boolean bool) { return maker.Return(maker.Literal(CTC_BOOLEAN, bool ? 1 : 0)); } + + private boolean jcAnnotatedTypeInit; + private Class<?> jcAnnotatedTypeClass = null; + private Field jcAnnotatedTypeUnderlyingTypeField = null; + + private JCExpression unnotate(JCExpression type) { + if (!isJcAnnotatedType(type)) return type; + if (jcAnnotatedTypeUnderlyingTypeField == null) return type; + try { + return (JCExpression) jcAnnotatedTypeUnderlyingTypeField.get(type); + } catch (Exception ignore) {} + return type; + } + + private boolean isJcAnnotatedType(JCExpression o) { + if (o == null) return false; + if (!jcAnnotatedTypeInit) { + try { + jcAnnotatedTypeClass = Class.forName("com.sun.tools.javac.tree.JCTree$JCAnnotatedType", false, o.getClass().getClassLoader()); + jcAnnotatedTypeUnderlyingTypeField = jcAnnotatedTypeClass.getDeclaredField("underlyingType"); + } + catch (Exception ignore) {} + jcAnnotatedTypeInit = true; + } + return jcAnnotatedTypeClass == o.getClass(); + } } diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 0fcaa5f8..9120fa07 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -177,7 +177,9 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } // Set the names of the builder classes. - String builderClassName = td.name.toString() + "Builder"; + String builderClassNameTemplate = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); + if (builderClassNameTemplate == null || builderClassNameTemplate.isEmpty()) builderClassNameTemplate = "*Builder"; + String builderClassName = builderClassNameTemplate.replace("*", td.name.toString()); String builderImplClassName = builderClassName + "Impl"; JCTree extendsClause = Javac.getExtendsClause(td); JCExpression superclassBuilderClassExpression = null; @@ -189,11 +191,11 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } if (extendsClause instanceof JCFieldAccess) { Name superclassClassName = ((JCFieldAccess)extendsClause).getIdentifier(); - String superclassBuilderClassName = superclassClassName + "Builder"; + String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName); superclassBuilderClassExpression = tdParent.getTreeMaker().Select((JCFieldAccess) extendsClause, - tdParent.toName(superclassBuilderClassName)); + tdParent.toName(superclassBuilderClassName)); } else if (extendsClause != null) { - String superclassBuilderClassName = extendsClause.toString() + "Builder"; + String superclassBuilderClassName = builderClassNameTemplate.replace("*", extendsClause.toString()); superclassBuilderClassExpression = chainDots(tdParent, extendsClause.toString(), superclassBuilderClassName); } // If there is no superclass, superclassBuilderClassExpression is still == null at this point. diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 3477c51c..1532319f 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -692,7 +692,10 @@ public class PrettyPrinter extends JCTree.Visitor { @Override public void visitTypeApply(JCTypeApply tree) { print(tree.clazz); print("<"); + boolean temp = innermostArrayBracketsAreVarargs; + innermostArrayBracketsAreVarargs = false; print(tree.arguments, ", "); + innermostArrayBracketsAreVarargs = temp; print(">"); } diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 0e74dfaf..24c1216e 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -122,6 +122,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchEcjTransformers(sm, ecjOnly); patchExtensionMethod(sm, ecjOnly); patchRenameField(sm); + patchNullCheck(sm); if (reloadExistingClasses) sm.reloadClasses(instrumentation); } @@ -774,4 +775,24 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .build()); } } + + private static void patchNullCheck(ScriptManager sm) { + /* Avoid warnings caused by the null check generated for lombok.NonNull if NonNullByDefault is used. */ + + /* Avoid "Redundant null check: comparing '@NonNull String' against null" */ + sm.addScript(ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.compiler.problem.ProblemReporter", "expressionNonNullComparison", "boolean", "org.eclipse.jdt.internal.compiler.ast.Expression", "boolean")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .valueMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "returnTrue", "boolean", "java.lang.Object")) + .request(StackRequest.PARAM1) + .transplant().build()); + + /* Avoid "Dead code" */ + sm.addScript(ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.compiler.problem.ProblemReporter", "fakeReachable", "void", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .request(StackRequest.PARAM1) + .transplant().build()); + } + } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index b32c99cd..0c66bb31 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -21,16 +21,27 @@ */ package lombok.eclipse.agent; +import lombok.permit.Permit; +import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; 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.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression; import org.eclipse.jdt.internal.compiler.ast.ImportReference; +import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; @@ -42,13 +53,15 @@ import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -import lombok.permit.Permit; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import java.lang.reflect.Field; +import static lombok.Lombok.sneakyThrow; import static lombok.eclipse.Eclipse.poss; import static lombok.eclipse.handlers.EclipseHandlerUtil.makeType; +import static org.eclipse.jdt.core.compiler.CategorizedProblem.CAT_TYPE; public class PatchVal { @@ -263,15 +276,11 @@ public class PatchVal { resolved = null; } if (resolved != null) { - if (resolved.getClass().getSimpleName().startsWith("IntersectionTypeBinding")) { - // We intentionally deconstruct these into simply 'Object', because picking an arbitrary type amongst the intersection feels worse. - } else { - try { - replacement = makeType(resolved, local.type, false); - if (!decomponent) init.resolvedType = replacement.resolveType(scope); - } catch (Exception e) { - // Some type thing failed. - } + try { + replacement = makeType(resolved, local.type, false); + if (!decomponent) init.resolvedType = replacement.resolveType(scope); + } catch (Exception e) { + // Some type thing failed. } } } @@ -357,11 +366,106 @@ public class PatchVal { } private static TypeBinding resolveForExpression(Expression collection, BlockScope scope) { + CompilationUnitDeclaration referenceContext = scope.compilationUnitScope().referenceContext; + ProblemReporter oldProblemReporter = referenceContext.problemReporter; + referenceContext.problemReporter = new ProblemReporter(DefaultErrorHandlingPolicies.exitOnFirstError(), + oldProblemReporter.options, oldProblemReporter.problemFactory); try { return collection.resolveType(scope); } catch (ArrayIndexOutOfBoundsException e) { // Known cause of issues; for example: val e = mth("X"), where mth takes 2 arguments. return null; + } catch (AbortCompilation e) { + if (collection instanceof ConditionalExpression) { + ConditionalExpression cexp = (ConditionalExpression) collection; + Expression ifTrue = cexp.valueIfTrue; + Expression ifFalse = cexp.valueIfFalse; + TypeBinding ifTrueResolvedType = ifTrue.resolvedType; + CategorizedProblem problem = e.problem; + if (ifTrueResolvedType != null && ifFalse.resolvedType == null && problem.getCategoryID() == CAT_TYPE) { + CompilationResult compilationResult = e.compilationResult; + CategorizedProblem[] problems = compilationResult.problems; + int problemCount = compilationResult.problemCount; + for (int i = 0; i < problemCount; ++i) { + if (problems[i] == problem) { + problems[i] = null; + if (i + 1 < problemCount) { + System.arraycopy(problems, i + 1, problems, i, problemCount - i + 1); + } + break; + } + } + compilationResult.removeProblem(problem); + if (!compilationResult.hasErrors()) { + clearIgnoreFurtherInvestigationField(scope.referenceContext()); + setValue(getField(CompilationResult.class, "hasMandatoryErrors"), compilationResult, false); + } + + if (ifFalse instanceof FunctionalExpression) { + FunctionalExpression functionalExpression = (FunctionalExpression) ifFalse; + functionalExpression.setExpectedType(ifTrueResolvedType); + } + if (ifFalse.resolvedType == null) { + ifFalse.resolve(scope); + } + + return ifTrueResolvedType; + } + } + throw e; + } finally { + referenceContext.problemReporter = oldProblemReporter; + } + } + + private static void clearIgnoreFurtherInvestigationField(ReferenceContext currentContext) { + if (currentContext instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) currentContext; + methodDeclaration.ignoreFurtherInvestigation = false; + } else if (currentContext instanceof LambdaExpression) { + LambdaExpression lambdaExpression = (LambdaExpression) currentContext; + setValue(getField(LambdaExpression.class, "ignoreFurtherInvestigation"), lambdaExpression, false); + + Scope parent = lambdaExpression.enclosingScope.parent; + while (parent != null) { + switch(parent.kind) { + case Scope.CLASS_SCOPE: + case Scope.METHOD_SCOPE: + ReferenceContext parentAST = parent.referenceContext(); + if (parentAST != lambdaExpression) { + clearIgnoreFurtherInvestigationField(parentAST); + return; + } + default: + parent = parent.parent; + break; + } + } + + } else if (currentContext instanceof TypeDeclaration) { + TypeDeclaration typeDeclaration = (TypeDeclaration) currentContext; + typeDeclaration.ignoreFurtherInvestigation = false; + } else if (currentContext instanceof CompilationUnitDeclaration) { + CompilationUnitDeclaration typeDeclaration = (CompilationUnitDeclaration) currentContext; + typeDeclaration.ignoreFurtherInvestigation = false; + } else { + throw new UnsupportedOperationException("clearIgnoreFurtherInvestigationField for " + currentContext.getClass()); + } + } + + private static void setValue(Field field, Object object, Object value) { + try { + field.set(object, value); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } + } + + private static Field getField(Class clazz, String name) { + try { + return Permit.getField(clazz, name); + } catch (NoSuchFieldException e) { + throw sneakyThrow(e); } } } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index 3741aba8..563beab1 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -315,7 +315,17 @@ final class PatchFixesHider { } return result; } - + + public static boolean isGenerated(org.eclipse.jdt.internal.compiler.ast.ASTNode node) { + boolean result = false; + try { + result = node.getClass().getField("$generatedBy").get(node) != null; + } catch (Exception e) { + // better to assume it isn't generated + } + return result; + } + public static boolean isListRewriteOnGeneratedNode(org.eclipse.jdt.core.dom.rewrite.ListRewrite rewrite) { return isGenerated(rewrite.getParent()); } |