diff options
Diffstat (limited to 'src')
9 files changed, 152 insertions, 36 deletions
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 8b330816..ed18dd45 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -798,18 +798,19 @@ public class EclipseHandlerUtil { } } - private static final Map<FieldDeclaration, GetterMethod> generatedLazyGetters = new WeakHashMap<FieldDeclaration, GetterMethod>(); + private static final Map<FieldDeclaration, Object> generatedLazyGettersWithPrimitiveBoolean = new WeakHashMap<FieldDeclaration, Object>(); + private static final Object MARKER = new Object(); static void registerCreatedLazyGetter(FieldDeclaration field, char[] methodName, TypeReference returnType) { - generatedLazyGetters.put(field, new GetterMethod(methodName, returnType)); + if (!nameEquals(returnType.getTypeName(), "boolean") || returnType.dimensions() > 0) return; + generatedLazyGettersWithPrimitiveBoolean.put(field, MARKER); } private static GetterMethod findGetter(EclipseNode field) { FieldDeclaration fieldDeclaration = (FieldDeclaration) field.get(); - GetterMethod gm = generatedLazyGetters.get(fieldDeclaration); - if (gm != null) return gm; + boolean forceBool = generatedLazyGettersWithPrimitiveBoolean.containsKey(fieldDeclaration); TypeReference fieldType = fieldDeclaration.type; - boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0; + boolean isBoolean = forceBool || (nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0); EclipseNode typeNode = field.up(); for (String potentialGetterName : toAllGetterNames(field, isBoolean)) { diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index eec41577..25d47870 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -156,20 +156,29 @@ public class HandleConstructor { } public void generateConstructor(EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, ASTNode source) { + boolean staticConstrRequired = staticName != null && !staticName.equals(""); + if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; if (skipIfConstructorExists) { for (EclipseNode child : typeNode.down()) { if (child.getKind() == Kind.ANNOTATION) { if (annotationTypeMatches(NoArgsConstructor.class, child) || annotationTypeMatches(AllArgsConstructor.class, child) || - annotationTypeMatches(RequiredArgsConstructor.class, child)) + annotationTypeMatches(RequiredArgsConstructor.class, child)) { + + if (staticConstrRequired) { + // @Data has asked us to generate a constructor, but we're going to skip this instruction, as an explicit 'make a constructor' annotation + // will take care of it. However, @Data also wants a specific static name; this will be ignored; the appropriate way to do this is to use + // the 'staticName' parameter of the @XArgsConstructor you've stuck on your type. + // We should warn that we're ignoring @Data's 'staticConstructor' param. + typeNode.addWarning("Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.", source.sourceStart, source.sourceEnd); + } return; + } } } } - boolean staticConstrRequired = staticName != null && !staticName.equals(""); - ConstructorDeclaration constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source); injectMethod(typeNode, constr); if (staticConstrRequired) { diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index 6da60907..73bb38b0 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -456,12 +456,18 @@ public class JavacResolution { if (upper == null || upper.toString().equals("java.lang.Object")) { return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); } + 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)); } else { return maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), typeToJCTree(lower, ast, false, false)); } } if (upper != null) { + if (upper.getTypeArguments().contains(type)) { + return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); + } return typeToJCTree(upper, ast, allowCompound, allowVoid); } diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index a2463728..d701b41e 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -43,12 +43,10 @@ import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; -import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCReturn; import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; @@ -154,20 +152,29 @@ public class HandleConstructor { } public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JavacNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, JavacNode source) { + boolean staticConstrRequired = staticName != null && !staticName.equals(""); + if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; if (skipIfConstructorExists) { for (JavacNode child : typeNode.down()) { if (child.getKind() == Kind.ANNOTATION) { if (annotationTypeMatches(NoArgsConstructor.class, child) || annotationTypeMatches(AllArgsConstructor.class, child) || - annotationTypeMatches(RequiredArgsConstructor.class, child)) + annotationTypeMatches(RequiredArgsConstructor.class, child)) { + + if (staticConstrRequired) { + // @Data has asked us to generate a constructor, but we're going to skip this instruction, as an explicit 'make a constructor' annotation + // will take care of it. However, @Data also wants a specific static name; this will be ignored; the appropriate way to do this is to use + // the 'staticName' parameter of the @XArgsConstructor you've stuck on your type. + // We should warn that we're ignoring @Data's 'staticConstructor' param. + source.addWarning("Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used."); + } return; + } } } } - boolean staticConstrRequired = staticName != null && !staticName.equals(""); - JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source.get()); injectMethod(typeNode, constr); if (staticConstrRequired) { @@ -259,16 +266,7 @@ public class HandleConstructor { for (JavacNode fieldNode : fields) { JCVariableDecl field = (JCVariableDecl) fieldNode.get(); - JCExpression pType; - if (field.vartype instanceof JCIdent) pType = maker.Ident(((JCIdent)field.vartype).name); - else if (field.vartype instanceof JCTypeApply) { - JCTypeApply typeApply = (JCTypeApply) field.vartype; - ListBuffer<JCExpression> tArgs = ListBuffer.lb(); - for (JCExpression arg : typeApply.arguments) tArgs.append(arg); - pType = maker.TypeApply(typeApply.clazz, tArgs.toList()); - } else { - pType = field.vartype; - } + JCExpression pType = cloneType(maker, field.vartype, source); List<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN); List<JCAnnotation> nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN); JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables)), field.name, pType, null); diff --git a/src/core/lombok/javac/handlers/HandleExtensionMethod.java b/src/core/lombok/javac/handlers/HandleExtensionMethod.java index 2df6be45..92d7c0e4 100644 --- a/src/core/lombok/javac/handlers/HandleExtensionMethod.java +++ b/src/core/lombok/javac/handlers/HandleExtensionMethod.java @@ -55,7 +55,6 @@ import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; -import com.sun.tools.javac.tree.TreeMaker; /** * Handles the {@link ExtensionMethod} annotation for javac. @@ -180,10 +179,7 @@ public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMetho Type firstArgType = types.erasure(extensionMethodType.asMethodType().argtypes.get(0)); if (!types.isAssignable(receiverType, firstArgType)) continue; methodCall.args = methodCall.args.prepend(receiver); - - TreeMaker maker = annotationNode.getTreeMaker(); - JCIdent extensionClassIdent = maker.Ident(annotationNode.toName(extensionProvider.toString())); - methodCall.meth = maker.Select(extensionClassIdent, annotationNode.toName(methodName)); + methodCall.meth = chainDotsString(annotationNode, extensionProvider.toString() + "." + methodName); return; } } diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java index 04668317..1ba8d131 100644 --- a/src/core/lombok/javac/handlers/HandleSynchronized.java +++ b/src/core/lombok/javac/handlers/HandleSynchronized.java @@ -78,16 +78,16 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; } - TreeMaker maker = methodNode.getTreeMaker(); + TreeMaker maker = methodNode.getTreeMaker().at(ast.pos); if (fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS) { if (!autoMake) { annotationNode.addError("The field " + lockName + " does not exist."); return; } - JCExpression objectType = chainDots(methodNode, "java", "lang", "Object"); + JCExpression objectType = chainDots(methodNode, ast.pos, "java", "lang", "Object"); //We use 'new Object[0];' because unlike 'new Object();', empty arrays *ARE* serializable! - JCNewArray newObjectArray = maker.NewArray(chainDots(methodNode, "java", "lang", "Object"), + JCNewArray newObjectArray = maker.NewArray(chainDots(methodNode, ast.pos, "java", "lang", "Object"), List.<JCExpression>of(maker.Literal(Javac.getCtcInt(TypeTags.class, "INT"), 0)), null); JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (isStatic ? Flags.STATIC : 0)), @@ -99,7 +99,7 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { JCExpression lockNode; if (isStatic) { - lockNode = chainDots(methodNode, methodNode.up().getName(), lockName); + lockNode = chainDots(methodNode, ast.pos, methodNode.up().getName(), lockName); } else { lockNode = maker.Select(maker.Ident(methodNode.toName("this")), methodNode.toName(lockName)); } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index f2cdee6d..b0f2a890 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -45,14 +45,17 @@ import lombok.experimental.Accessors; import lombok.javac.Javac; import lombok.javac.JavacNode; +import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.TypeTags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCAssign; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.tree.JCTree.JCLiteral; @@ -60,9 +63,13 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWildcard; +import com.sun.tools.javac.tree.JCTree.TypeBoundKind; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -244,6 +251,7 @@ public class JavacHandlerUtil { * Only does this if the DeleteLombokAnnotations class is in the context. */ public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class<? extends Annotation> annotationType) { + if (inNetbeansEditor(annotation)) return; if (!annotation.shouldDeleteLombokAnnotations()) return; JavacNode parentNode = annotation.directUp(); switch (parentNode.getKind()) { @@ -274,6 +282,7 @@ public class JavacHandlerUtil { } public static void deleteImportFromCompilationUnit(JavacNode node, String name) { + if (inNetbeansEditor(node)) return; if (!node.shouldDeleteLombokAnnotations()) return; ListBuffer<JCTree> newDefs = ListBuffer.lb(); @@ -768,6 +777,8 @@ public class JavacHandlerUtil { * In javac, dotted access of any kind, from {@code java.lang.String} to {@code var.methodName} * is represented by a fold-left of {@code Select} nodes with the leftmost string represented by * a {@code Ident} node. This method generates such an expression. + * <p> + * The position of the generated node(s) will be unpositioned (-1). * * For example, maker.Select(maker.Select(maker.Ident(NAME[java]), NAME[lang]), NAME[String]). * @@ -775,12 +786,30 @@ public class JavacHandlerUtil { * @see com.sun.tools.javac.tree.JCTree.JCFieldAccess */ public static JCExpression chainDots(JavacNode node, String... elems) { + return chainDots(node, -1, elems); + } + + /** + * In javac, dotted access of any kind, from {@code java.lang.String} to {@code var.methodName} + * is represented by a fold-left of {@code Select} nodes with the leftmost string represented by + * a {@code Ident} node. This method generates such an expression. + * <p> + * The position of the generated node(s) will be equal to the {@code pos} parameter. + * + * For example, maker.Select(maker.Select(maker.Ident(NAME[java]), NAME[lang]), NAME[String]). + * + * @see com.sun.tools.javac.tree.JCTree.JCIdent + * @see com.sun.tools.javac.tree.JCTree.JCFieldAccess + */ + public static JCExpression chainDots(JavacNode node, int pos, String... elems) { assert elems != null; assert elems.length > 0; - JCExpression e = node.getTreeMaker().Ident(node.toName(elems[0])); + TreeMaker maker = node.getTreeMaker(); + if (pos != -1) maker = maker.at(pos); + JCExpression e = maker.Ident(node.toName(elems[0])); for (int i = 1 ; i < elems.length ; i++) { - e = node.getTreeMaker().Select(e, node.toName(elems[i])); + e = maker.Select(e, node.toName(elems[i])); } return e; @@ -798,7 +827,7 @@ public class JavacHandlerUtil { * @see com.sun.tools.javac.tree.JCTree.JCFieldAccess */ public static JCExpression chainDotsString(JavacNode node, String elems) { - return chainDots(node, elems.split("\\.")); + return chainDots(node, elems.split("\\.")); } /** @@ -922,4 +951,71 @@ public class JavacHandlerUtil { return node; } + + /** + * Creates a full clone of a given javac AST type node. Every part is cloned (every identifier, every select, every wildcard, every type apply). + * + * If there's any node in the tree that we don't know how to clone, that part isn't cloned. However, we wouldn't know what could possibly show up that we + * can't currently clone; that's just a safeguard. + * + * This should be used if the type looks the same in the code, but resolves differently. For example, a static method that has some generics in it named after + * the class's own parameter, but as its a static method, the static method's notion of {@code T} is different from the class notion of {@code T}. If you're duplicating + * a type used in the class context, you need to use this method. + */ + public static JCExpression cloneType(TreeMaker maker, JCExpression in, JCTree source) { + JCExpression out = cloneType0(maker, in); + if (out != null) recursiveSetGeneratedBy(out, source); + return out; + } + + private static JCExpression cloneType0(TreeMaker maker, JCTree in) { + if (in == null) return null; + + if (in instanceof JCPrimitiveTypeTree) return (JCExpression) in; + + if (in instanceof JCIdent) { + return maker.Ident(((JCIdent) in).name); + } + + if (in instanceof JCFieldAccess) { + JCFieldAccess fa = (JCFieldAccess) in; + return maker.Select(cloneType0(maker, fa.selected), fa.name); + } + + if (in instanceof JCArrayTypeTree) { + JCArrayTypeTree att = (JCArrayTypeTree) in; + return maker.TypeArray(cloneType0(maker, att.elemtype)); + } + + if (in instanceof JCTypeApply) { + JCTypeApply ta = (JCTypeApply) in; + ListBuffer<JCExpression> lb = ListBuffer.lb(); + for (JCExpression typeArg : ta.arguments) { + lb.append(cloneType0(maker, typeArg)); + } + return maker.TypeApply(cloneType0(maker, ta.clazz), lb.toList()); + } + + if (in instanceof JCWildcard) { + JCWildcard w = (JCWildcard) in; + JCExpression newInner = cloneType0(maker, w.inner); + TypeBoundKind newKind; + switch (w.getKind()) { + case SUPER_WILDCARD: + newKind = maker.TypeBoundKind(BoundKind.SUPER); + break; + case EXTENDS_WILDCARD: + newKind = maker.TypeBoundKind(BoundKind.EXTENDS); + break; + default: + case UNBOUNDED_WILDCARD: + newKind = maker.TypeBoundKind(BoundKind.UNBOUND); + break; + } + return maker.Wildcard(newKind, newInner); + } + + // This is somewhat unsafe, but it's better than outright throwing an exception here. Returning null will just cause an exception down the pipeline. + return (JCExpression) in; + } } diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index a639a1f6..3f521274 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -381,6 +381,7 @@ public class Delombok { } JavaCompiler delegate = compiler.processAnnotations(compiler.enterTrees(toJavacList(roots))); + delegate.flow(delegate.attribute(delegate.todo)); for (JCCompilationUnit unit : roots) { DelombokResult result = new DelombokResult(catcher.getComments(unit), unit, force || options.isChanged(unit)); if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged"); diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 095928ad..2f47ccf6 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -1037,8 +1037,17 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { throw new UncheckedIOException(e); } } - + + private boolean isNoArgsSuperCall(JCExpression expr) { + if (!(expr instanceof JCMethodInvocation)) return false; + JCMethodInvocation tree = (JCMethodInvocation) expr; + if (!tree.typeargs.isEmpty() || !tree.args.isEmpty()) return false; + if (!(tree.meth instanceof JCIdent)) return false; + return ((JCIdent) tree.meth).name.toString().equals("super"); + } + public void visitExec(JCExpressionStatement tree) { + if (isNoArgsSuperCall(tree.expr)) return; try { printExpr(tree.expr); if (prec == TreeInfo.notExpression) print(";"); |