mirror of
https://github.com/tiennm99/lombok.git
synced 2026-08-13 14:23:12 +00:00
'val' now works for member types whose outers have generics. (issue #343)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user