From aa8a627349bb68f376b98847b6f73c2c89e989fd Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 30 May 2011 22:04:46 +0200 Subject: tracking if an annotation has been handled or not is now no longer done via the LombokAST object. Instead its tracked more directly in an attempt to avoid having to write all handlers as idempotent, and just in case issue #164 is a race condition (the handled-or-not is a synchronized CAS check). This does break API for other plugins, but the fix is trivial: Just make your 'handle' method return void. That 'we won't call you again' business in the decks never quite worked right anyway. Also, you might want to call Javac.(recursive)setHandledBy when you generate nodes, now. --- src/core/lombok/core/LombokNode.java | 45 +---------- .../lombok/eclipse/EclipseAnnotationHandler.java | 6 +- src/core/lombok/eclipse/HandlerLibrary.java | 29 +++++--- src/core/lombok/eclipse/TransformEclipseAST.java | 22 ++---- .../eclipse/handlers/EclipseHandlerUtil.java | 69 ++--------------- .../lombok/eclipse/handlers/HandleCleanup.java | 18 ++--- .../lombok/eclipse/handlers/HandleConstructor.java | 23 +++--- src/core/lombok/eclipse/handlers/HandleData.java | 8 +- .../eclipse/handlers/HandleEqualsAndHashCode.java | 14 ++-- src/core/lombok/eclipse/handlers/HandleGetter.java | 38 +++++----- src/core/lombok/eclipse/handlers/HandleLog.java | 26 +++---- .../lombok/eclipse/handlers/HandlePrintAST.java | 7 +- src/core/lombok/eclipse/handlers/HandleSetter.java | 35 ++++----- .../eclipse/handlers/HandleSneakyThrows.java | 16 ++-- .../eclipse/handlers/HandleSynchronized.java | 14 ++-- .../lombok/eclipse/handlers/HandleToString.java | 14 ++-- src/core/lombok/javac/HandlerLibrary.java | 30 +++++--- src/core/lombok/javac/Javac.java | 44 ++++++++++- src/core/lombok/javac/JavacAnnotationHandler.java | 6 +- src/core/lombok/javac/JavacTransformer.java | 22 ++---- src/core/lombok/javac/handlers/HandleCleanup.java | 24 +++--- .../lombok/javac/handlers/HandleConstructor.java | 54 +++++++------- src/core/lombok/javac/handlers/HandleData.java | 14 ++-- src/core/lombok/javac/handlers/HandleDelegate.java | 17 ++--- .../javac/handlers/HandleEqualsAndHashCode.java | 49 ++++++------ src/core/lombok/javac/handlers/HandleGetter.java | 86 +++++++++++----------- src/core/lombok/javac/handlers/HandleLog.java | 42 ++++++----- src/core/lombok/javac/handlers/HandlePrintAST.java | 6 +- src/core/lombok/javac/handlers/HandleSetter.java | 56 +++++++------- .../lombok/javac/handlers/HandleSneakyThrows.java | 31 ++++---- .../lombok/javac/handlers/HandleSynchronized.java | 25 +++---- src/core/lombok/javac/handlers/HandleToString.java | 31 ++++---- src/core/lombok/javac/handlers/HandleVal.java | 12 ++- .../lombok/javac/handlers/JavacHandlerUtil.java | 30 +++----- 34 files changed, 433 insertions(+), 530 deletions(-) diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java index 90e55757..4989f304 100644 --- a/src/core/lombok/core/LombokNode.java +++ b/src/core/lombok/core/LombokNode.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,13 +45,6 @@ public abstract class LombokNode, L extends LombokNode children; protected L parent; - /** This flag has no specified meaning; you can set and retrieve it. - * - * In practice, for annotation nodes it means: Some AnnotationHandler finished whatever changes were required, - * and for all other nodes it means: This node was made by a lombok operation. - */ - protected boolean handled; - /** structurally significant are those nodes that can be annotated in java 1.6 or are method-like toplevels, * so fields, local declarations, method arguments, methods, types, the Compilation Unit itself, and initializers. */ protected boolean isStructurallySignificant; @@ -84,8 +77,8 @@ public abstract class LombokNode, L extends LombokNode, L extends LombokNode(children); } - /** - * returns the value of the 'handled' flag. - * - * @see #handled - */ - public boolean isHandled() { - return handled; - } - - /** - * Sets the handled flag, then returns itself for chaining. - * - * @see #handled - */ - @SuppressWarnings("unchecked") - public L setHandled() { - this.handled = true; - return (L)this; - } - /** * Convenient shortcut to the owning ast object's top method. * @@ -308,18 +281,6 @@ public abstract class LombokNode, L extends LombokNode annotation, org.eclipse.jdt.internal.compiler.ast.Annotation ast, EclipseNode annotationNode); + void handle(AnnotationValues annotation, org.eclipse.jdt.internal.compiler.ast.Annotation ast, EclipseNode annotationNode); } diff --git a/src/core/lombok/eclipse/HandlerLibrary.java b/src/core/lombok/eclipse/HandlerLibrary.java index ba7f891a..109f6fe1 100644 --- a/src/core/lombok/eclipse/HandlerLibrary.java +++ b/src/core/lombok/eclipse/HandlerLibrary.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.WeakHashMap; import lombok.Lombok; import lombok.core.AnnotationValues; @@ -38,6 +39,7 @@ import lombok.core.TypeLibrary; import lombok.core.TypeResolver; import lombok.core.AnnotationValues.AnnotationValueDecodeFail; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; @@ -65,10 +67,10 @@ public class HandlerLibrary { this.annotationClass = annotationClass; } - public boolean handle(org.eclipse.jdt.internal.compiler.ast.Annotation annotation, + public void handle(org.eclipse.jdt.internal.compiler.ast.Annotation annotation, final EclipseNode annotationNode) { AnnotationValues annValues = Eclipse.createAnnotation(annotationClass, annotationNode); - return handler.handle(annValues, annotation, annotationNode); + handler.handle(annValues, annotation, annotationNode); } } @@ -126,6 +128,15 @@ public class HandlerLibrary { } } + private static final Map handledMap = new WeakHashMap(); + private static final Object MARKER = new Object(); + + private boolean checkAndSetHandled(ASTNode node) { + synchronized (handledMap) { + return handledMap.put(node, MARKER) != MARKER; + } + } + /** * Handles the provided annotation node by first finding a qualifying instance of * {@link EclipseAnnotationHandler} and if one exists, calling it with a freshly cooked up @@ -143,15 +154,15 @@ public class HandlerLibrary { * @param annotationNode The Lombok AST Node representing the Annotation AST Node. * @param annotation 'node.get()' - convenience parameter. */ - public boolean handle(CompilationUnitDeclaration ast, EclipseNode annotationNode, - org.eclipse.jdt.internal.compiler.ast.Annotation annotation) { + public void handleAnnotation(CompilationUnitDeclaration ast, EclipseNode annotationNode, org.eclipse.jdt.internal.compiler.ast.Annotation annotation) { + if (!checkAndSetHandled(annotation)) return; + String pkgName = annotationNode.getPackageDeclaration(); Collection imports = annotationNode.getImportStatements(); TypeResolver resolver = new TypeResolver(typeLibrary, pkgName, imports); TypeReference rawType = annotation.type; - if (rawType == null) return false; - boolean handled = false; + if (rawType == null) return; for (String fqn : resolver.findTypeMatches(annotationNode, toQualifiedName(annotation.type.getTypeName()))) { boolean isPrintAST = fqn.equals(PrintAST.class.getName()); if (isPrintAST == skipPrintAST) continue; @@ -160,15 +171,13 @@ public class HandlerLibrary { if (container == null) continue; try { - handled |= container.handle(annotation, annotationNode); + container.handle(annotation, annotationNode); } catch (AnnotationValueDecodeFail fail) { fail.owner.setError(fail.getMessage(), fail.idx); } catch (Throwable t) { Eclipse.error(ast, String.format("Lombok annotation handler %s failed", container.handler.getClass()), t); } } - - return handled; } /** diff --git a/src/core/lombok/eclipse/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java index aada3ca4..314c8a7d 100644 --- a/src/core/lombok/eclipse/TransformEclipseAST.java +++ b/src/core/lombok/eclipse/TransformEclipseAST.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -168,38 +168,28 @@ public class TransformEclipseAST { private static class AnnotationVisitor extends EclipseASTAdapter { @Override public void visitAnnotationOnField(FieldDeclaration field, EclipseNode annotationNode, Annotation annotation) { - if (annotationNode.isHandled()) return; CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get(); - boolean handled = handlers.handle(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) { - if (annotationNode.isHandled()) return; CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get(); - boolean handled = handlers.handle(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnLocal(LocalDeclaration local, EclipseNode annotationNode, Annotation annotation) { - if (annotationNode.isHandled()) return; CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get(); - boolean handled = handlers.handle(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnMethod(AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) { - if (annotationNode.isHandled()) return; CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get(); - boolean handled = handlers.handle(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnType(TypeDeclaration type, EclipseNode annotationNode, Annotation annotation) { - if (annotationNode.isHandled()) return; CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get(); - boolean handled = handlers.handle(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index d16e3ead..0eae12f2 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * Copyright © 2009-2011 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -332,9 +332,7 @@ public class EclipseHandlerUtil { char[] fName = def.name; if (fName == null) continue; if (fieldName.equals(new String(fName))) { - EclipseNode existing = node.getNodeFor(def); - if (existing == null || !existing.isHandled()) return MemberExistsResult.EXISTS_BY_USER; - return MemberExistsResult.EXISTS_BY_LOMBOK; + return Eclipse.getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } } } @@ -369,11 +367,7 @@ public class EclipseHandlerUtil { char[] mName = def.selector; if (mName == null) continue; boolean nameEquals = caseSensitive ? methodName.equals(new String(mName)) : methodName.equalsIgnoreCase(new String(mName)); - if (nameEquals) { - EclipseNode existing = node.getNodeFor(def); - if (existing == null || !existing.isHandled()) return MemberExistsResult.EXISTS_BY_USER; - return MemberExistsResult.EXISTS_BY_LOMBOK; - } + if (nameEquals) return Eclipse.getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } } } @@ -397,9 +391,7 @@ public class EclipseHandlerUtil { if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) { if (def instanceof ConstructorDeclaration) { if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue; - EclipseNode existing = node.getNodeFor(def); - if (existing == null || !existing.isHandled()) return MemberExistsResult.EXISTS_BY_USER; - return MemberExistsResult.EXISTS_BY_LOMBOK; + return Eclipse.getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } } } @@ -407,55 +399,6 @@ public class EclipseHandlerUtil { return MemberExistsResult.NOT_EXISTS; } - /** - * Returns the constructor that's already been generated by lombok. - * Provide any node that represents the type (TypeDeclaration) to look in, or any child node thereof. - */ - public static EclipseNode getExistingLombokConstructor(EclipseNode node) { - while (node != null && !(node.get() instanceof TypeDeclaration)) { - node = node.up(); - } - - if (node == null) return null; - - if (node.get() instanceof TypeDeclaration) { - for (AbstractMethodDeclaration def : ((TypeDeclaration)node.get()).methods) { - if (def instanceof ConstructorDeclaration) { - if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue; - EclipseNode existing = node.getNodeFor(def); - if (existing.isHandled()) return existing; - } - } - } - - return null; - } - - /** - * Returns the method that's already been generated by lombok with the given name. - * Provide any node that represents the type (TypeDeclaration) to look in, or any child node thereof. - */ - public static EclipseNode getExistingLombokMethod(String methodName, EclipseNode node) { - while (node != null && !(node.get() instanceof TypeDeclaration)) { - node = node.up(); - } - - if (node == null) return null; - - if (node.get() instanceof TypeDeclaration) { - for (AbstractMethodDeclaration def : ((TypeDeclaration)node.get()).methods) { - char[] mName = def.selector; - if (mName == null) continue; - if (methodName.equals(new String(mName))) { - EclipseNode existing = node.getNodeFor(def); - if (existing.isHandled()) return existing; - } - } - } - - return null; - } - /** * Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}. * The field carries the @{@link SuppressWarnings}("all") annotation. @@ -487,7 +430,7 @@ public class EclipseHandlerUtil { } } - type.add(field, Kind.FIELD).recursiveSetHandled(); + type.add(field, Kind.FIELD); } private static boolean hasClinit(TypeDeclaration parent) { @@ -573,7 +516,7 @@ public class EclipseHandlerUtil { parent.methods = newArray; } - type.add(method, Kind.METHOD).recursiveSetHandled(); + type.add(method, Kind.METHOD); } private static final char[] ALL = "all".toCharArray(); diff --git a/src/core/lombok/eclipse/handlers/HandleCleanup.java b/src/core/lombok/eclipse/handlers/HandleCleanup.java index 9a63ce47..4f9615b6 100644 --- a/src/core/lombok/eclipse/handlers/HandleCleanup.java +++ b/src/core/lombok/eclipse/handlers/HandleCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * Copyright © 2009-2011 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -59,23 +59,23 @@ import org.mangosdk.spi.ProviderFor; */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleCleanup implements EclipseAnnotationHandler { - public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { String cleanupName = annotation.getInstance().value(); if (cleanupName.length() == 0) { annotationNode.addError("cleanupName cannot be the empty string."); - return true; + return; } if (annotationNode.up().getKind() != Kind.LOCAL) { annotationNode.addError("@Cleanup is legal only on local variable declarations."); - return true; + return; } LocalDeclaration decl = (LocalDeclaration)annotationNode.up().get(); if (decl.initialization == null) { annotationNode.addError("@Cleanup variable declarations need to be initialized."); - return true; + return; } EclipseNode ancestor = annotationNode.up().directUp(); @@ -94,12 +94,12 @@ public class HandleCleanup implements EclipseAnnotationHandler { statements = ((SwitchStatement)blockNode).statements; } else { annotationNode.addError("@Cleanup is legal only on a local variable declaration inside a block."); - return true; + return; } if (statements == null) { annotationNode.addError("LOMBOK BUG: Parent block does not contain any statements."); - return true; + return; } int start = 0; @@ -109,7 +109,7 @@ public class HandleCleanup implements EclipseAnnotationHandler { if (start == statements.length) { annotationNode.addError("LOMBOK BUG: Can't find this local variable declaration inside its parent."); - return true; + return; } start++; //We start with try{} *AFTER* the var declaration. @@ -205,8 +205,6 @@ public class HandleCleanup implements EclipseAnnotationHandler { } ancestor.rebuild(); - - return true; } private MessageSend preventNullAnalysis(Annotation ast, Expression expr) { diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index db26beed..e0715961 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -73,34 +73,32 @@ import org.mangosdk.spi.ProviderFor; public class HandleConstructor { @ProviderFor(EclipseAnnotationHandler.class) public static class HandleNoArgsConstructor implements EclipseAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { EclipseNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, NoArgsConstructor.class.getSimpleName())) return true; + if (!checkLegality(typeNode, annotationNode, NoArgsConstructor.class.getSimpleName())) return; NoArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); String staticName = ann.staticName(); - if (level == AccessLevel.NONE) return true; + if (level == AccessLevel.NONE) return; List fields = new ArrayList(); Annotation[] onConstructor = getAndRemoveAnnotationParameter(ast, "onConstructor"); new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, onConstructor, false, false, ast); - return true; } } @ProviderFor(EclipseAnnotationHandler.class) public static class HandleRequiredArgsConstructor implements EclipseAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { EclipseNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, RequiredArgsConstructor.class.getSimpleName())) return true; + if (!checkLegality(typeNode, annotationNode, RequiredArgsConstructor.class.getSimpleName())) return; RequiredArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); String staticName = ann.staticName(); @SuppressWarnings("deprecation") boolean suppressConstructorProperties = ann.suppressConstructorProperties(); - if (level == AccessLevel.NONE) return true; + if (level == AccessLevel.NONE) return; Annotation[] onConstructor = getAndRemoveAnnotationParameter(ast, "onConstructor"); new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, onConstructor, false, suppressConstructorProperties, ast); - return true; } } @@ -119,15 +117,15 @@ public class HandleConstructor { @ProviderFor(EclipseAnnotationHandler.class) public static class HandleAllArgsConstructor implements EclipseAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { EclipseNode typeNode = annotationNode.up(); - if (!checkLegality(typeNode, annotationNode, AllArgsConstructor.class.getSimpleName())) return true; + if (!checkLegality(typeNode, annotationNode, AllArgsConstructor.class.getSimpleName())) return; AllArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); String staticName = ann.staticName(); @SuppressWarnings("deprecation") boolean suppressConstructorProperties = ann.suppressConstructorProperties(); - if (level == AccessLevel.NONE) return true; + if (level == AccessLevel.NONE) return; List fields = new ArrayList(); for (EclipseNode child : typeNode.down()) { if (child.getKind() != Kind.FIELD) continue; @@ -135,13 +133,12 @@ public class HandleConstructor { if (!EclipseHandlerUtil.filterField(fieldDecl)) continue; // Skip initialized final fields. - if (((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0) && fieldDecl.initialization != null) return false; + if (((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0) && fieldDecl.initialization != null) return; fields.add(child); } Annotation[] onConstructor = getAndRemoveAnnotationParameter(ast, "onConstructor"); new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, onConstructor, false, suppressConstructorProperties, ast); - return true; } } diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java index 0a28ccf4..9b3d7e51 100644 --- a/src/core/lombok/eclipse/handlers/HandleData.java +++ b/src/core/lombok/eclipse/handlers/HandleData.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,7 @@ import org.mangosdk.spi.ProviderFor; */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleData implements EclipseAnnotationHandler { - public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { Data ann = annotation.getInstance(); EclipseNode typeNode = annotationNode.up(); @@ -49,7 +49,7 @@ public class HandleData implements EclipseAnnotationHandler { if (typeDecl == null || notAClass) { annotationNode.addError("@Data is only supported on a class."); - return false; + return; } //Careful: Generate the public static constructor (if there is one) LAST, so that any attempt to @@ -63,7 +63,5 @@ public class HandleData implements EclipseAnnotationHandler { new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode); new HandleToString().generateToStringForType(typeNode, annotationNode); new HandleConstructor().generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, ast); - - return false; } } diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 8ee7272c..3be8fdfa 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * Copyright © 2009-2011 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -116,7 +116,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler annotation, + @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { EqualsAndHashCode ann = annotation.getInstance(); List excludes = Arrays.asList(ann.exclude()); @@ -137,10 +137,10 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler excludes, List includes, + public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List excludes, List includes, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) { assert excludes == null || includes == null; @@ -153,7 +153,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess) { diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index f39e55b5..3af09afb 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -131,7 +131,7 @@ public class HandleGetter implements EclipseAnnotationHandler { createGetterForField(level, fieldNode, fieldNode, pos, false, onMethod, lazy); } - public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { EclipseNode node = annotationNode.up(); Getter annotationInstance = annotation.getInstance(); AccessLevel level = annotationInstance.value(); @@ -140,46 +140,46 @@ public class HandleGetter implements EclipseAnnotationHandler { if (lazy) { annotationNode.addWarning("'lazy' does not work with AccessLevel.NONE."); } - return true; + return; } - if (node == null) return false; + if (node == null) return; Annotation[] onMethod = getAndRemoveAnnotationParameter(ast, "onMethod"); - if (node.getKind() == Kind.FIELD) { - return createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, lazy); - } - if (node.getKind() == Kind.TYPE) { + switch (node.getKind()) { + case FIELD: + createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, lazy); + break; + case TYPE: if (onMethod != null && onMethod.length != 0) annotationNode.addError("'onMethod' is not supported for @Getter on a type."); if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type."); - return generateGetterForType(node, annotationNode, level, false); + generateGetterForType(node, annotationNode, level, false); + break; } - return false; } - private boolean createGetterForFields(AccessLevel level, Collection fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod, boolean lazy) { + private void createGetterForFields(AccessLevel level, Collection fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod, boolean lazy) { for (EclipseNode fieldNode : fieldNodes) { createGetterForField(level, fieldNode, errorNode, source, whineIfExists, onMethod, lazy); } - return true; } - private boolean createGetterForField(AccessLevel level, + private void createGetterForField(AccessLevel level, EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod, boolean lazy) { if (fieldNode.getKind() != Kind.FIELD) { errorNode.addError("@Getter is only supported on a class or a field."); - return true; + return; } FieldDeclaration field = (FieldDeclaration) fieldNode.get(); if (lazy) { if ((field.modifiers & ClassFileConstants.AccPrivate) == 0 || (field.modifiers & ClassFileConstants.AccFinal) == 0) { errorNode.addError("'lazy' requires the field to be private and final."); - return true; + return; } if (field.initialization == null) { errorNode.addError("'lazy' requires field initialization."); - return true; + return; } } @@ -193,7 +193,7 @@ public class HandleGetter implements EclipseAnnotationHandler { for (String altName : TransformationsUtil.toAllGetterNames(fieldName, isBoolean)) { switch (methodExists(altName, fieldNode, false)) { case EXISTS_BY_LOMBOK: - return true; + return; case EXISTS_BY_USER: if (whineIfExists) { String altNameExpl = ""; @@ -201,7 +201,7 @@ public class HandleGetter implements EclipseAnnotationHandler { errorNode.addWarning( String.format("Not generating %s(): A method with that name already exists%s", getterName, altNameExpl)); } - return true; + return; default: case NOT_EXISTS: //continue scanning the other alt names. @@ -215,8 +215,6 @@ public class HandleGetter implements EclipseAnnotationHandler { } injectMethod(fieldNode.up(), method); - - return true; } private MethodDeclaration generateGetter(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, boolean lazy) { diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index be856208..a51d8e7e 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -51,7 +51,7 @@ public class HandleLog { throw new UnsupportedOperationException(); } - public static boolean processAnnotation(LoggingFramework framework, AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + public static void processAnnotation(LoggingFramework framework, AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { EclipseNode owner = annotationNode.up(); switch (owner.getKind()) { case TYPE: @@ -64,22 +64,22 @@ public class HandleLog { if (typeDecl == null || notAClass) { annotationNode.addError("@Log is legal only on classes and enums."); - return false; + return; } if (fieldExists("log", owner) != MemberExistsResult.NOT_EXISTS) { annotationNode.addWarning("Field 'log' already exists."); - return true; + return; } ClassLiteralAccess loggingType = selfType(owner, source); injectField(owner, createField(framework, source, loggingType)); owner.rebuild(); - return true; + break; default: annotationNode.addError("@Log is legal only on types."); - return true; + break; } } @@ -154,8 +154,8 @@ public class HandleLog { */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleCommonsLog implements EclipseAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { - return processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode); + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode); } } @@ -164,8 +164,8 @@ public class HandleLog { */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleJulLog implements EclipseAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { - return processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode); + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode); } } @@ -174,8 +174,8 @@ public class HandleLog { */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleLog4jLog implements EclipseAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { - return processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode); + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode); } } @@ -184,8 +184,8 @@ public class HandleLog { */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleSlf4jLog implements EclipseAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { - return processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode); + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode); } } diff --git a/src/core/lombok/eclipse/handlers/HandlePrintAST.java b/src/core/lombok/eclipse/handlers/HandlePrintAST.java index 580a54a2..be86a566 100644 --- a/src/core/lombok/eclipse/handlers/HandlePrintAST.java +++ b/src/core/lombok/eclipse/handlers/HandlePrintAST.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,8 +40,8 @@ import lombok.eclipse.EclipseNode; */ @ProviderFor(EclipseAnnotationHandler.class) public class HandlePrintAST implements EclipseAnnotationHandler { - public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { - if (!annotationNode.isCompleteParse()) return false; + public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + if (!annotationNode.isCompleteParse()) return; PrintStream stream = System.out; String fileName = annotation.getInstance().outfile(); @@ -52,6 +52,5 @@ public class HandlePrintAST implements EclipseAnnotationHandler { } annotationNode.up().traverse(new EclipseASTVisitor.Printer(annotation.getInstance().printContent(), stream)); - return true; } } diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 945495c6..ac3ff2a2 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -120,40 +120,37 @@ public class HandleSetter implements EclipseAnnotationHandler { createSetterForField(level, fieldNode, fieldNode, pos, false, onMethod, onParam); } - public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { EclipseNode node = annotationNode.up(); AccessLevel level = annotation.getInstance().value(); - if (level == AccessLevel.NONE) return true; - - if (node == null) return false; + if (level == AccessLevel.NONE || node == null) return; Annotation[] onMethod = getAndRemoveAnnotationParameter(ast, "onMethod"); Annotation[] onParam = getAndRemoveAnnotationParameter(ast, "onParam"); - if (node.getKind() == Kind.FIELD) { - return createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, onParam); - - } - if (node.getKind() == Kind.TYPE) { + switch (node.getKind()) { + case FIELD: + createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, onParam); + break; + case TYPE: if (onMethod != null && onMethod.length != 0) annotationNode.addError("'onMethod' is not supported for @Setter on a type."); if (onParam != null && onParam.length != 0) annotationNode.addError("'onParam' is not supported for @Setter on a type."); - return generateSetterForType(node, annotationNode, level, false); + generateSetterForType(node, annotationNode, level, false); + break; } - return false; } - private boolean createSetterForFields(AccessLevel level, Collection fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod , Annotation[] onParam) { + private void createSetterForFields(AccessLevel level, Collection fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod , Annotation[] onParam) { for (EclipseNode fieldNode : fieldNodes) { createSetterForField(level, fieldNode, errorNode, source, whineIfExists, onMethod, onParam); } - return true; } - private boolean createSetterForField(AccessLevel level, + private void createSetterForField(AccessLevel level, EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod , Annotation[] onParam) { if (fieldNode.getKind() != Kind.FIELD) { errorNode.addError("@Setter is only supported on a class or a field."); - return true; + return; } FieldDeclaration field = (FieldDeclaration) fieldNode.get(); @@ -166,7 +163,7 @@ public class HandleSetter implements EclipseAnnotationHandler { for (String altName : TransformationsUtil.toAllSetterNames(new String(field.name), isBoolean)) { switch (methodExists(altName, fieldNode, false)) { case EXISTS_BY_LOMBOK: - return true; + return; case EXISTS_BY_USER: if (whineIfExists) { String altNameExpl = ""; @@ -174,7 +171,7 @@ public class HandleSetter implements EclipseAnnotationHandler { errorNode.addWarning( String.format("Not generating %s(): A method with that name already exists%s", setterName, altNameExpl)); } - return true; + return; default: case NOT_EXISTS: //continue scanning the other alt names. @@ -188,8 +185,6 @@ public class HandleSetter implements EclipseAnnotationHandler { } injectMethod(fieldNode.up(), method); - - return true; } private MethodDeclaration generateSetter(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, Annotation[] onParam) { diff --git a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java index 38f22b2a..4b36d688 100644 --- a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -69,7 +69,7 @@ public class HandleSneakyThrows implements EclipseAnnotationHandler annotation, Annotation source, EclipseNode annotationNode) { + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { List exceptionNames = annotation.getRawExpressions("value"); List exceptions = new ArrayList(); @@ -101,10 +101,10 @@ public class HandleSneakyThrows implements EclipseAnnotationHandler exceptions) { + private void handleMethod(EclipseNode annotation, AbstractMethodDeclaration method, List exceptions) { if (method.isAbstract()) { annotation.addError("@SneakyThrows can only be used on concrete methods."); - return true; + return; } - if (method.statements == null) return false; + if (method.statements == null) return; Statement[] contents = method.statements; @@ -156,8 +156,6 @@ public class HandleSneakyThrows implements EclipseAnnotationHandler annotation, Annotation source, EclipseNode annotationNode) { + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { int p1 = source.sourceStart -1; int p2 = source.sourceStart -2; long pos = (((long)p1) << 32) | p2; EclipseNode methodNode = annotationNode.up(); if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof MethodDeclaration)) { annotationNode.addError("@Synchronized is legal only on methods."); - return true; + return; } MethodDeclaration method = (MethodDeclaration)methodNode.get(); if (method.isAbstract()) { annotationNode.addError("@Synchronized is legal only on concrete methods."); - return true; + return; } char[] lockName = annotation.getInstance().value().toCharArray(); @@ -83,7 +83,7 @@ public class HandleSynchronized implements EclipseAnnotationHandler { generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, FieldAccess.GETTER); } - public boolean handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { ToString ann = annotation.getInstance(); List excludes = Arrays.asList(ann.exclude()); List includes = Arrays.asList(ann.of()); @@ -118,10 +118,10 @@ public class HandleToString implements EclipseAnnotationHandler { FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; - return generateToString(typeNode, annotationNode, excludes, includes, ann.includeFieldNames(), callSuper, true, fieldAccess); + generateToString(typeNode, annotationNode, excludes, includes, ann.includeFieldNames(), callSuper, true, fieldAccess); } - public boolean generateToString(EclipseNode typeNode, EclipseNode errorNode, List excludes, List includes, + public void generateToString(EclipseNode typeNode, EclipseNode errorNode, List excludes, List includes, boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) { TypeDeclaration typeDecl = null; @@ -132,7 +132,6 @@ public class HandleToString implements EclipseAnnotationHandler { if (typeDecl == null || notAClass) { errorNode.addError("@ToString is only supported on a class or enum."); - return false; } if (callSuper == null) { @@ -165,15 +164,14 @@ public class HandleToString implements EclipseAnnotationHandler { case NOT_EXISTS: MethodDeclaration toString = createToString(typeNode, nodesForToString, includeFieldNames, callSuper, errorNode.get(), fieldAccess); injectMethod(typeNode, toString); - return true; + break; case EXISTS_BY_LOMBOK: - return true; + break; default: case EXISTS_BY_USER: if (whineIfExists) { errorNode.addWarning("Not generating toString(): A method with that name already exists"); } - return true; } } diff --git a/src/core/lombok/javac/HandlerLibrary.java b/src/core/lombok/javac/HandlerLibrary.java index 12a5a370..0c753c02 100644 --- a/src/core/lombok/javac/HandlerLibrary.java +++ b/src/core/lombok/javac/HandlerLibrary.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.WeakHashMap; import javax.annotation.processing.Messager; import javax.tools.Diagnostic; @@ -37,6 +38,7 @@ import lombok.core.TypeLibrary; import lombok.core.TypeResolver; import lombok.core.AnnotationValues.AnnotationValueDecodeFail; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -74,8 +76,8 @@ public class HandlerLibrary { return handler.isResolutionBased(); } - public boolean handle(final JavacNode node) { - return handler.handle(Javac.createAnnotation(annotationClass, node), (JCAnnotation)node.get(), node); + public void handle(final JavacNode node) { + handler.handle(Javac.createAnnotation(annotationClass, node), (JCAnnotation)node.get(), node); } } @@ -141,6 +143,15 @@ public class HandlerLibrary { if (t != null) t.printStackTrace(); } + private static final Map handledMap = new WeakHashMap(); + private static final Object MARKER = new Object(); + + private boolean checkAndSetHandled(JCTree node) { + synchronized (handledMap) { + return handledMap.put(node, MARKER) != MARKER; + } + } + /** * Handles the provided annotation node by first finding a qualifying instance of * {@link JavacAnnotationHandler} and if one exists, calling it with a freshly cooked up @@ -158,10 +169,11 @@ public class HandlerLibrary { * @param node The Lombok AST Node representing the Annotation AST Node. * @param annotation 'node.get()' - convenience parameter. */ - public boolean handleAnnotation(JCCompilationUnit unit, JavacNode node, JCAnnotation annotation) { + public void handleAnnotation(JCCompilationUnit unit, JavacNode node, JCAnnotation annotation) { + if (!checkAndSetHandled(annotation)) return; + TypeResolver resolver = new TypeResolver(typeLibrary, node.getPackageDeclaration(), node.getImportStatements()); String rawType = annotation.annotationType.toString(); - boolean handled = false; for (String fqn : resolver.findTypeMatches(node, rawType)) { boolean isPrintAST = fqn.equals(PrintAST.class.getName()); if (isPrintAST && phase != 2) continue; @@ -170,9 +182,9 @@ public class HandlerLibrary { if (container == null) continue; try { - if (container.isResolutionBased() && phase == 1) handled |= container.handle(node); - if (!container.isResolutionBased() && phase == 0) handled |= container.handle(node); - if (container.annotationClass == PrintAST.class && phase == 2) handled |= container.handle(node); + if (container.isResolutionBased() && phase == 1) container.handle(node); + if (!container.isResolutionBased() && phase == 0) container.handle(node); + if (container.annotationClass == PrintAST.class && phase == 2) container.handle(node); } catch (AnnotationValueDecodeFail fail) { fail.owner.setError(fail.getMessage(), fail.idx); } catch (Throwable t) { @@ -181,8 +193,6 @@ public class HandlerLibrary { javacError(String.format("Lombok annotation handler %s failed on " + sourceName, container.handler.getClass()), t); } } - - return handled; } /** diff --git a/src/core/lombok/javac/Javac.java b/src/core/lombok/javac/Javac.java index 8eb56e1d..64e8ee27 100644 --- a/src/core/lombok/javac/Javac.java +++ b/src/core/lombok/javac/Javac.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; import lombok.Lombok; import lombok.core.AST.Kind; @@ -45,6 +46,7 @@ import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** @@ -194,4 +196,44 @@ public class Javac { throw Lombok.sneakyThrow(e); } } + + private static class MarkingScanner extends TreeScanner { + private final JCTree source; + + MarkingScanner(JCTree source) { + this.source = source; + } + + @Override public void scan(JCTree tree) { + setGeneratedBy(tree, source); + super.scan(tree); + } + } + + private static Map generatedNodes = new WeakHashMap(); + + public static JCTree getGeneratedBy(JCTree node) { + synchronized (generatedNodes) { + return generatedNodes.get(node); + } + } + + public static boolean isGenerated(JCTree node) { + return getGeneratedBy(node) != null; + } + + public static T recursiveSetGeneratedBy(T node, JCTree source) { + setGeneratedBy(node, source); + node.accept(new MarkingScanner(source)); + + return node; + } + + public static T setGeneratedBy(T node, JCTree source) { + synchronized (generatedNodes) { + if (source == null) generatedNodes.remove(node); + else generatedNodes.put(node, source); + } + return node; + } } diff --git a/src/core/lombok/javac/JavacAnnotationHandler.java b/src/core/lombok/javac/JavacAnnotationHandler.java index ee330ecb..3e9f6660 100644 --- a/src/core/lombok/javac/JavacAnnotationHandler.java +++ b/src/core/lombok/javac/JavacAnnotationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2011 Reinier Zwitserloot and Roel Spilker. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -51,10 +51,8 @@ public interface JavacAnnotationHandler { * @param annotationNode The Lombok AST wrapper around the 'ast' parameter. You can use this object * to travel back up the chain (something javac AST can't do) to the parent of the annotation, as well * as access useful methods such as generating warnings or errors focused on the annotation. - * @return {@code true} if you don't want to be called again about this annotation during this - * compile session (you've handled it), or {@code false} to indicate you aren't done yet. */ - boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode); + void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode); /** * Return true if this handler requires resolution. diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java index beef6924..7423d061 100644 --- a/src/core/lombok/javac/JavacTransformer.java +++ b/src/core/lombok/javac/JavacTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * Copyright © 2009-2011 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -88,38 +88,28 @@ public class JavacTransformer { private class AnnotationVisitor extends JavacASTAdapter { @Override public void visitAnnotationOnType(JCClassDecl type, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnField(JCVariableDecl field, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnMethod(JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnMethodArgument(JCVariableDecl argument, JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } @Override public void visitAnnotationOnLocal(JCVariableDecl local, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); + handlers.handleAnnotation(top, annotationNode, annotation); } } } diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java index b681ab28..eb4b7987 100644 --- a/src/core/lombok/javac/handlers/HandleCleanup.java +++ b/src/core/lombok/javac/handlers/HandleCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * Copyright © 2009-2011 Reinier Zwitserloot, Roel Spilker and Robbert Jan Gr