diff options
author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-03-06 05:24:39 +0100 |
---|---|---|
committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-03-06 05:25:03 +0100 |
commit | 732c7257e1db44b83b4748c93969cd74195d416f (patch) | |
tree | e2997ce7fdc9bcfe0521703502eb9e0b6c4dad01 | |
parent | 5e1ee5cb0dc26dd9a2a064edd7700abec5aa98fa (diff) | |
download | lombok-732c7257e1db44b83b4748c93969cd74195d416f.tar.gz lombok-732c7257e1db44b83b4748c93969cd74195d416f.tar.bz2 lombok-732c7257e1db44b83b4748c93969cd74195d416f.zip |
[fixes #2358] self-referential generics could cause endless loops in javac.
... unfortunately eclipse's val resolver is now very slightly worse in very exotic circumstances - spent about 4 hours trying to fix it, can't figure it out, let's move on.
8 files changed, 88 insertions, 19 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 001302c0..f56ae524 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -5,6 +5,7 @@ Lombok Changelog * BREAKING CHANGE: mapstruct users should now add a dependency to lombok-mapstruct-binding. This solves compiling modules with lombok (and mapstruct). * FEATURE: Similar to `@Builder`, you can now configure a `@SuperBuilder`'s 'setter' prefixes via `@SuperBuilder(setterPrefix = "set")` for example. We still discourage doing this. [Pull Request #2357](https://github.com/rzwitserloot/lombok/pull/2357). * FEATURE: If using `@Synchronized("lockVar")`, if `lockVar` is referring to a static field, the code lombok generates no longer causes a warning about accessing a static entity incorrectly. [Issue #678](https://github.com/rzwitserloot/lombok/issues/678) +* BUGFIX: Using `val` in combination with values whose generics include wildcards that reference themselves would cause a `StackOverflowError` in javac. [Issue #2358](https://github.com/rzwitserloot/lombok/issues/2358). * BUGFIX: Using `@SuperBuilder` on a class that has some fairly convoluted generics usage would fail with 'Wrong number of type arguments'. [Issue #2359](https://github.com/rzwitserloot/lombok/issues/2359) [Pull Request #2362](https://github.com/rzwitserloot/lombok/pull/2362) * BUGFIX: Various lombok annotations on classes nested inside enums or interfaces would cause errors in eclipse. [Issue #2369](https://github.com/rzwitserloot/lombok/issues/2369) * BUGFIX: Trying to add `@ExtensionMethod`s with exactly 2 arguments would fail in eclipse. [Issue #1441](https://github.com/rzwitserloot/lombok/issues/1441) [Pull Request #2376](https://github.com/rzwitserloot/lombok/pull/2376) thanks to __@Rawi01__. diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index 7f940d2a..9a0077a7 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 The Project Lombok Authors. + * Copyright (C) 2011-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 @@ -33,10 +33,6 @@ import java.util.Map; import javax.lang.model.type.TypeKind; import javax.tools.JavaFileObject; -import lombok.Lombok; -import lombok.core.debug.AssertionLogger; -import lombok.permit.Permit; - import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.code.Symtab; @@ -58,11 +54,16 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; +import lombok.Lombok; +import lombok.core.debug.AssertionLogger; +import lombok.permit.Permit; + public class JavacResolution { private final Attr attr; private final CompilerMessageSuppressor messageSuppressor; @@ -286,7 +287,7 @@ public class JavacResolution { } public static JCExpression typeToJCTree(Type type, JavacAST ast, boolean allowVoid) throws TypeNotConvertibleException { - return typeToJCTree(type, ast, false, allowVoid); + return typeToJCTree(type, ast, false, allowVoid, false); } public static JCExpression createJavaLangObject(JavacAST ast) { @@ -297,7 +298,7 @@ public class JavacResolution { return out; } - private static JCExpression typeToJCTree(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid) throws TypeNotConvertibleException { + private static JCExpression typeToJCTree(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid, boolean allowCapture) throws TypeNotConvertibleException { int dims = 0; Type type0 = type; while (type0 instanceof ArrayType) { @@ -305,7 +306,7 @@ public class JavacResolution { type0 = ((ArrayType) type0).elemtype; } - JCExpression result = typeToJCTree0(type0, ast, allowCompound, allowVoid); + JCExpression result = typeToJCTree0(type0, ast, allowCompound, allowVoid, allowCapture); while (dims > 0) { result = ast.getTreeMaker().TypeArray(result); dims--; @@ -313,7 +314,7 @@ public class JavacResolution { return result; } - private static JCExpression typeToJCTree0(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid) throws TypeNotConvertibleException { + private static JCExpression typeToJCTree0(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid, boolean allowCapture) throws TypeNotConvertibleException { // NB: There's such a thing as maker.Type(type), but this doesn't work very well; it screws up anonymous classes, captures, and adds an extra prefix dot for some reason too. // -- so we write our own take on that here. @@ -337,21 +338,33 @@ public class JavacResolution { List<Type> ifaces = ((ClassType) type).interfaces_field; Type supertype = ((ClassType) type).supertype_field; if (isObject(supertype) && ifaces != null && ifaces.length() > 0) { - return typeToJCTree(ifaces.get(0), ast, allowCompound, allowVoid); + return typeToJCTree(ifaces.get(0), ast, allowCompound, allowVoid, allowCapture); } - if (supertype != null) return typeToJCTree(supertype, ast, allowCompound, allowVoid); + if (supertype != null) return typeToJCTree(supertype, ast, allowCompound, allowVoid, allowCapture); } throw new TypeNotConvertibleException("Anonymous inner class"); } - if (type instanceof CapturedType || type instanceof WildcardType) { + if (type instanceof WildcardType || type instanceof CapturedType) { Type lower, upper; if (type instanceof WildcardType) { - upper = ((WildcardType)type).getExtendsBound(); - lower = ((WildcardType)type).getSuperBound(); + upper = ((WildcardType) type).getExtendsBound(); + lower = ((WildcardType) type).getSuperBound(); } else { lower = type.getLowerBound(); upper = type.getUpperBound(); + if (allowCapture) { + BoundKind bk = ((CapturedType) type).wildcard.kind; + if (bk == BoundKind.UNBOUND) { + return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); + } else if (bk == BoundKind.EXTENDS) { + lower = null; + upper = ((CapturedType) type).wildcard.type; + } else if (bk == BoundKind.SUPER) { + lower = ((CapturedType) type).wildcard.type; + upper = null; + } + } } if (allowCompound) { if (lower == null || CTC_BOT.equals(typeTag(lower))) { @@ -361,16 +374,20 @@ public class JavacResolution { if (upper.getTypeArguments().contains(type)) { return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); } - return maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), typeToJCTree(upper, ast, false, false)); + JCExpression bound = typeToJCTree(upper, ast, false, false, true); + if (bound instanceof JCWildcard) return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); + return maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), bound); } else { - return maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), typeToJCTree(lower, ast, false, false)); + JCExpression bound = typeToJCTree(lower, ast, false, false, true); + if (bound instanceof JCWildcard) return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); + return maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), bound); } } if (upper != null) { if (upper.getTypeArguments().contains(type)) { return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); } - return typeToJCTree(upper, ast, allowCompound, allowVoid); + return typeToJCTree(upper, ast, allowCompound, allowVoid, true); } return createJavaLangObject(ast); @@ -380,7 +397,7 @@ public class JavacResolution { if (symbol.isLocal()) { qName = symbol.getSimpleName().toString(); } else if (symbol.type != null && symbol.type.getEnclosingType() != null && typeTag(symbol.type.getEnclosingType()).equals(typeTag("CLASS"))) { - replacement = typeToJCTree0(type.getEnclosingType(), ast, false, false); + replacement = typeToJCTree0(type.getEnclosingType(), ast, false, false, false); qName = symbol.getSimpleName().toString(); } else { qName = symbol.getQualifiedName().toString(); @@ -409,7 +426,7 @@ public class JavacResolution { private static JCExpression genericsToJCTreeNodes(List<Type> generics, JavacAST ast, JCExpression rawTypeNode) throws TypeNotConvertibleException { if (generics != null && !generics.isEmpty()) { ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); - for (Type t : generics) args.append(typeToJCTree(t, ast, true, false)); + for (Type t : generics) args.append(typeToJCTree(t, ast, true, false, true)); return ast.getTreeMaker().TypeApply(rawTypeNode, args.toList()); } diff --git a/test/transform/resource/after-delombok/ValWeirdTypes.java b/test/transform/resource/after-delombok/ValWeirdTypes.java index 8b399fe8..bc18fdac 100644 --- a/test/transform/resource/after-delombok/ValWeirdTypes.java +++ b/test/transform/resource/after-delombok/ValWeirdTypes.java @@ -37,6 +37,7 @@ public class ValWeirdTypes<Z> { final java.util.List<? super java.lang.Number> d = upper; List<?> unbound = lower; final java.util.List<?> e = unbound; + final java.lang.Object f = unbound.get(0); } public void testCompound() { final java.util.ArrayList<java.lang.String> a = new ArrayList<String>(); diff --git a/test/transform/resource/after-delombok/ValWithSelfRefGenerics.java b/test/transform/resource/after-delombok/ValWithSelfRefGenerics.java new file mode 100644 index 00000000..11cbf43f --- /dev/null +++ b/test/transform/resource/after-delombok/ValWithSelfRefGenerics.java @@ -0,0 +1,14 @@ +public class ValWithSelfRefGenerics { + public void run(Thing<? extends Comparable<?>> thing, Thing<?> thing2, java.util.List<? extends Number> z) { + final java.util.List<? extends java.lang.Number> y = z; + final Thing<? extends java.lang.Comparable<?>> x = thing; + final Thing<?> w = thing2; + final java.lang.Comparable<?> v = thing2.get(); + } +} + +class Thing<T extends Comparable<? super T>> { + public T get() { + return null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValWeirdTypes.java b/test/transform/resource/after-ecj/ValWeirdTypes.java index e98b9753..401a8b7e 100644 --- a/test/transform/resource/after-ecj/ValWeirdTypes.java +++ b/test/transform/resource/after-ecj/ValWeirdTypes.java @@ -44,6 +44,7 @@ public class ValWeirdTypes<Z> { final @val java.util.List<? super java.lang.Number> d = upper; List<?> unbound = lower; final @val java.util.List<?> e = unbound; + final @val java.lang.Object f = unbound.get(0); } public void testCompound() { final @val java.util.ArrayList<java.lang.String> a = new ArrayList<String>(); diff --git a/test/transform/resource/after-ecj/ValWithSelfRefGenerics.java b/test/transform/resource/after-ecj/ValWithSelfRefGenerics.java new file mode 100644 index 00000000..3984e203 --- /dev/null +++ b/test/transform/resource/after-ecj/ValWithSelfRefGenerics.java @@ -0,0 +1,20 @@ +import lombok.val; +public class ValWithSelfRefGenerics { + public ValWithSelfRefGenerics() { + super(); + } + public void run(Thing<? extends Comparable<?>> thing, Thing<?> thing2, java.util.List<? extends Number> z) { + final @val java.util.List<? extends java.lang.Number> y = z; + final @val Thing<? extends java.lang.Comparable<?>> x = thing; + final @val Thing<?> w = thing2; + final @val java.lang.Object v = thing2.get(); + } +} +class Thing<T extends Comparable<? super T>> { + Thing() { + super(); + } + public T get() { + return null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValWeirdTypes.java b/test/transform/resource/before/ValWeirdTypes.java index 157ffc76..8dd63e86 100644 --- a/test/transform/resource/before/ValWeirdTypes.java +++ b/test/transform/resource/before/ValWeirdTypes.java @@ -44,6 +44,7 @@ public class ValWeirdTypes<Z> { val d = upper; List<?> unbound = lower; val e = unbound; + val f = unbound.get(0); } public void testCompound() { diff --git a/test/transform/resource/before/ValWithSelfRefGenerics.java b/test/transform/resource/before/ValWithSelfRefGenerics.java new file mode 100644 index 00000000..d0532606 --- /dev/null +++ b/test/transform/resource/before/ValWithSelfRefGenerics.java @@ -0,0 +1,14 @@ +import lombok.val; +public class ValWithSelfRefGenerics { + public void run(Thing<? extends Comparable<?>> thing, Thing<?> thing2, java.util.List<? extends Number> z) { + val y = z; + val x = thing; + val w = thing2; + val v = thing2.get(); + } +} +class Thing<T extends Comparable<? super T>> { + public T get() { + return null; + } +} |