diff options
author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2012-02-14 16:31:48 +0100 |
---|---|---|
committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2012-02-14 16:31:48 +0100 |
commit | f259af306ff97acfcfed2dbfa2e9d4320079d69d (patch) | |
tree | c148411a3470cd92ffccb3c6010bc60cf5cc2405 | |
parent | 653104aa4e61672af91fb23367d9ab3f328a2b89 (diff) | |
download | lombok-f259af306ff97acfcfed2dbfa2e9d4320079d69d.tar.gz lombok-f259af306ff97acfcfed2dbfa2e9d4320079d69d.tar.bz2 lombok-f259af306ff97acfcfed2dbfa2e9d4320079d69d.zip |
'val' now works for member types whose outers have generics. (issue #343)
-rw-r--r-- | src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java | 55 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacResolution.java | 65 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleDelegate.java | 6 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleVal.java | 14 | ||||
-rw-r--r-- | test/core/src/lombok/AbstractRunTests.java | 3 |
5 files changed, 95 insertions, 48 deletions
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index c6d7eb41..0bc3cde2 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -30,6 +30,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -562,10 +563,38 @@ public class EclipseHandlerUtil { } } + // Keep moving up via 'binding.enclosingType()' and gather generics from each binding. We stop after a local type, or a static type, or a top-level type. + // 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 */ { + TypeBinding b = binding; + while (true) { + boolean isFinalStop = b.isLocalType() || !b.isMemberType() || b.enclosingType() == null; + + TypeReference[] tyParams = null; + if (b instanceof ParameterizedTypeBinding) { + ParameterizedTypeBinding paramized = (ParameterizedTypeBinding) b; + if (paramized.arguments != null) { + tyParams = new TypeReference[paramized.arguments.length]; + for (int i = 0; i < tyParams.length; i++) { + tyParams[i] = makeType(paramized.arguments[i], pos, true); + } + } + } + + params.add(tyParams); + if (isFinalStop) break; + b = b.enclosingType(); + } + } + char[][] parts; - if (binding.isLocalType() || binding.isTypeVariable()) { + if (binding.isTypeVariable()) { parts = new char[][] { binding.shortReadableName() }; + } else if (binding.isLocalType()) { + parts = new char[][] { binding.sourceName() }; } else { String[] pkg = new String(binding.qualifiedPackageName()).split("\\."); String[] name = new String(binding.qualifiedSourceName()).split("\\."); @@ -576,27 +605,25 @@ public class EclipseHandlerUtil { for (; ptr < pkg.length + name.length; ptr++) parts[ptr] = name[ptr - pkg.length].toCharArray(); } - TypeReference[] params = new TypeReference[0]; + while (params.size() < parts.length) params.add(null); + Collections.reverse(params); - if (binding instanceof ParameterizedTypeBinding) { - ParameterizedTypeBinding paramized = (ParameterizedTypeBinding) binding; - if (paramized.arguments != null) { - params = new TypeReference[paramized.arguments.length]; - for (int i = 0; i < params.length; i++) { - params[i] = makeType(paramized.arguments[i], pos, true); - } + boolean isParamized = false; + + for (TypeReference[] tyParams : params) { + if (tyParams != null) { + isParamized = true; + break; } } - - if (params.length > 0) { + if (isParamized) { if (parts.length > 1) { - TypeReference[][] typeArguments = new TypeReference[parts.length][]; - typeArguments[typeArguments.length - 1] = params; + TypeReference[][] typeArguments = params.toArray(new TypeReference[0][]); TypeReference result = new ParameterizedQualifiedTypeReference(parts, typeArguments, dims, poss(pos, parts.length)); setGeneratedBy(result, pos); return result; } - TypeReference result = new ParameterizedSingleTypeReference(parts[0], params, dims, pos(pos)); + TypeReference result = new ParameterizedSingleTypeReference(parts[0], params.get(0), dims, pos(pos)); setGeneratedBy(result, pos); return result; } diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index 29f261c6..da4b4762 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -362,18 +362,19 @@ public class JavacResolution { return iterableParams.isEmpty() ? syms.objectType : types.upperBound(iterableParams.head); } - public static JCExpression typeToJCTree(Type type, TreeMaker maker, JavacAST ast, boolean allowVoid) throws TypeNotConvertibleException { - return typeToJCTree(type, maker, ast, false, allowVoid); + public static JCExpression typeToJCTree(Type type, JavacAST ast, boolean allowVoid) throws TypeNotConvertibleException { + return typeToJCTree(type, ast, false, allowVoid); } - public static JCExpression createJavaLangObject(TreeMaker maker, JavacAST ast) { + public static JCExpression createJavaLangObject(JavacAST ast) { + TreeMaker maker = ast.getTreeMaker(); JCExpression out = maker.Ident(ast.toName("java")); out = maker.Select(out, ast.toName("lang")); out = maker.Select(out, ast.toName("Object")); return out; } - private static JCExpression typeToJCTree(Type type, TreeMaker maker, JavacAST ast, boolean allowCompound, boolean allowVoid) throws TypeNotConvertibleException { + private static JCExpression typeToJCTree(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid) throws TypeNotConvertibleException { int dims = 0; Type type0 = type; while (type0 instanceof ArrayType) { @@ -381,20 +382,22 @@ public class JavacResolution { type0 = ((ArrayType)type0).elemtype; } - JCExpression result = typeToJCTree0(type0, maker, ast, allowCompound, allowVoid); + JCExpression result = typeToJCTree0(type0, ast, allowCompound, allowVoid); while (dims > 0) { - result = maker.TypeArray(result); + result = ast.getTreeMaker().TypeArray(result); dims--; } return result; } - private static JCExpression typeToJCTree0(Type type, TreeMaker maker, JavacAST ast, boolean allowCompound, boolean allowVoid) throws TypeNotConvertibleException { + private static JCExpression typeToJCTree0(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid) 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. - if (type.tag == Javac.getCtcInt(TypeTags.class, "BOT")) return createJavaLangObject(maker, ast); - if (type.tag == Javac.getCtcInt(TypeTags.class, "VOID")) return allowVoid ? primitiveToJCTree(type.getKind(), maker) : createJavaLangObject(maker, ast); + TreeMaker maker = ast.getTreeMaker(); + + if (type.tag == Javac.getCtcInt(TypeTags.class, "BOT")) return createJavaLangObject(ast); + if (type.tag == Javac.getCtcInt(TypeTags.class, "VOID")) return allowVoid ? primitiveToJCTree(type.getKind(), maker) : createJavaLangObject(ast); if (type.isPrimitive()) return primitiveToJCTree(type.getKind(), maker); if (type.isErroneous()) throw new TypeNotConvertibleException("Type cannot be resolved"); @@ -411,9 +414,9 @@ public class JavacResolution { List<Type> ifaces = ((ClassType)type).interfaces_field; Type supertype = ((ClassType)type).supertype_field; if (ifaces != null && ifaces.length() == 1) { - return typeToJCTree(ifaces.get(0), maker, ast, allowCompound, allowVoid); + return typeToJCTree(ifaces.get(0), ast, allowCompound, allowVoid); } - if (supertype != null) return typeToJCTree(supertype, maker, ast, allowCompound, allowVoid); + if (supertype != null) return typeToJCTree(supertype, ast, allowCompound, allowVoid); } throw new TypeNotConvertibleException("Anonymous inner class"); } @@ -432,34 +435,52 @@ public class JavacResolution { if (upper == null || upper.toString().equals("java.lang.Object")) { return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); } - return maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), typeToJCTree(upper, maker, ast, false, false)); + return maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), typeToJCTree(upper, ast, false, false)); } else { - return maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), typeToJCTree(lower, maker, ast, false, false)); + return maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), typeToJCTree(lower, ast, false, false)); } } if (upper != null) { - return typeToJCTree(upper, maker, ast, allowCompound, allowVoid); + return typeToJCTree(upper, ast, allowCompound, allowVoid); } - return createJavaLangObject(maker, ast); + return createJavaLangObject(ast); + } + + String qName; + if (symbol.isLocal()) { + qName = symbol.getSimpleName().toString(); + } else if (symbol.type != null && symbol.type.getEnclosingType() != null && symbol.type.getEnclosingType().tag == TypeTags.CLASS) { + replacement = typeToJCTree0(type.getEnclosingType(), ast, false, false); + qName = symbol.getSimpleName().toString(); + } else { + qName = symbol.getQualifiedName().toString(); } - String qName = symbol.getQualifiedName().toString(); if (qName.isEmpty()) throw new TypeNotConvertibleException("unknown type"); if (qName.startsWith("<")) throw new TypeNotConvertibleException(qName); - String[] baseNames = symbol.getQualifiedName().toString().split("\\."); - replacement = maker.Ident(ast.toName(baseNames[0])); - for (int i = 1; i < baseNames.length; i++) { + String[] baseNames = qName.split("\\."); + int i = 0; + + if (replacement == null) { + replacement = maker.Ident(ast.toName(baseNames[0])); + i = 1; + } + for (; i < baseNames.length; i++) { replacement = maker.Select(replacement, ast.toName(baseNames[i])); } + return genericsToJCTreeNodes(generics, ast, replacement); + } + + private static JCExpression genericsToJCTreeNodes(List<Type> generics, JavacAST ast, JCExpression rawTypeNode) throws TypeNotConvertibleException { if (generics != null && !generics.isEmpty()) { ListBuffer<JCExpression> args = ListBuffer.lb(); - for (Type t : generics) args.append(typeToJCTree(t, maker, ast, true, false)); - replacement = maker.TypeApply(replacement, args.toList()); + for (Type t : generics) args.append(typeToJCTree(t, ast, true, false)); + return ast.getTreeMaker().TypeApply(rawTypeNode, args.toList()); } - return replacement; + return rawTypeNode; } private static JCExpression primitiveToJCTree(TypeKind kind, TreeMaker maker) throws TypeNotConvertibleException { diff --git a/src/core/lombok/javac/handlers/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java index 3674ae5a..ac0d61d1 100644 --- a/src/core/lombok/javac/handlers/HandleDelegate.java +++ b/src/core/lombok/javac/handlers/HandleDelegate.java @@ -277,7 +277,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { } JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annotations); - JCExpression returnType = JavacResolution.typeToJCTree((Type) sig.type.getReturnType(), maker, annotation.getAst(), true); + JCExpression returnType = JavacResolution.typeToJCTree((Type) sig.type.getReturnType(), annotation.getAst(), true); boolean useReturn = sig.type.getReturnType().getKind() != TypeKind.VOID; ListBuffer<JCVariableDecl> params = sig.type.getParameterTypes().isEmpty() ? null : new ListBuffer<JCVariableDecl>(); ListBuffer<JCExpression> args = sig.type.getParameterTypes().isEmpty() ? null : new ListBuffer<JCExpression>(); @@ -293,7 +293,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { } for (TypeMirror ex : sig.type.getThrownTypes()) { - thrown.append(JavacResolution.typeToJCTree((Type) ex, maker, annotation.getAst(), true)); + thrown.append(JavacResolution.typeToJCTree((Type) ex, annotation.getAst(), true)); } int idx = 0; @@ -301,7 +301,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { JCModifiers paramMods = maker.Modifiers(Flags.FINAL); String[] paramNames = sig.getParameterNames(); Name name = annotation.toName(paramNames[idx++]); - params.append(maker.VarDef(paramMods, name, JavacResolution.typeToJCTree((Type) param, maker, annotation.getAst(), true), null)); + params.append(maker.VarDef(paramMods, name, JavacResolution.typeToJCTree((Type) param, annotation.getAst(), true), null)); args.append(maker.Ident(name)); } diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index cb5d33b9..2ddd8cc6 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -82,7 +82,7 @@ public class HandleVal extends JavacASTAdapter { local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); } - local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst()); + local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); Type type; try { @@ -107,24 +107,24 @@ public class HandleVal extends JavacASTAdapter { if (rhsOfEnhancedForLoop != null) { Type componentType = JavacResolution.ifTypeIsIterableToComponent(type, localNode.getAst()); - if (componentType == null) replacement = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst()); - else replacement = JavacResolution.typeToJCTree(componentType, localNode.getTreeMaker(), localNode.getAst(), false); + if (componentType == null) replacement = JavacResolution.createJavaLangObject(localNode.getAst()); + else replacement = JavacResolution.typeToJCTree(componentType, localNode.getAst(), false); } else { - replacement = JavacResolution.typeToJCTree(type, localNode.getTreeMaker(), localNode.getAst(), false); + replacement = JavacResolution.typeToJCTree(type, localNode.getAst(), false); } if (replacement != null) { local.vartype = replacement; } else { - local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst()); + local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); } localNode.getAst().setChanged(); } catch (JavacResolution.TypeNotConvertibleException e) { localNode.addError("Cannot use 'val' here because initializer expression does not have a representable type: " + e.getMessage()); - local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst()); + local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); } } catch (RuntimeException e) { - local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst()); + local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); throw e; } finally { recursiveSetGeneratedBy(local.vartype, source); diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index 0cf7e0c7..b2200bbd 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -103,8 +103,7 @@ public abstract class AbstractRunTests { } try { compareContent(name, expectedMessages, actualMessages); - } - catch (Throwable e) { + } catch (Throwable e) { if (printErrors) { System.out.println("***** " + name + " *****"); System.out.println(e.getMessage()); |