diff options
-rw-r--r-- | src/lombok/eclipse/handlers/HandleSynchronized.java | 1 | ||||
-rw-r--r-- | src/lombok/javac/handlers/HandleData.java | 10 | ||||
-rw-r--r-- | src/lombok/javac/handlers/HandleSynchronized.java | 69 | ||||
-rw-r--r-- | src/lombok/javac/handlers/PKG.java | 46 |
4 files changed, 112 insertions, 14 deletions
diff --git a/src/lombok/eclipse/handlers/HandleSynchronized.java b/src/lombok/eclipse/handlers/HandleSynchronized.java index 15b81774..28e8bd1f 100644 --- a/src/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/lombok/eclipse/handlers/HandleSynchronized.java @@ -82,6 +82,7 @@ public class HandleSynchronized implements EclipseAnnotationHandler<Synchronized }; methodNode.rebuild(); + return true; } } diff --git a/src/lombok/javac/handlers/HandleData.java b/src/lombok/javac/handlers/HandleData.java index 54d85251..ddd9755c 100644 --- a/src/lombok/javac/handlers/HandleData.java +++ b/src/lombok/javac/handlers/HandleData.java @@ -68,27 +68,27 @@ public class HandleData implements JavacAnnotationHandler<Data> { String staticConstructorName = annotation.getInstance().staticConstructor(); - if ( constructorExists(typeNode) == MethodExistsResult.NOT_EXISTS ) { + if ( constructorExists(typeNode) == MemberExistsResult.NOT_EXISTS ) { JCMethodDecl constructor = createConstructor(staticConstructorName.equals(""), typeNode, nodesForConstructorAndToString); injectMethod(typeNode, constructor); } - if ( !staticConstructorName.isEmpty() && methodExists("of", typeNode) == MethodExistsResult.NOT_EXISTS ) { + if ( !staticConstructorName.isEmpty() && methodExists("of", typeNode) == MemberExistsResult.NOT_EXISTS ) { JCMethodDecl staticConstructor = createStaticConstructor(staticConstructorName, typeNode, nodesForConstructorAndToString); injectMethod(typeNode, staticConstructor); } - if ( methodExists("equals", typeNode) == MethodExistsResult.NOT_EXISTS ) { + if ( methodExists("equals", typeNode) == MemberExistsResult.NOT_EXISTS ) { JCMethodDecl method = createEquals(typeNode, nodesForEquality); injectMethod(typeNode, method); } - if ( methodExists("hashCode", typeNode) == MethodExistsResult.NOT_EXISTS ) { + if ( methodExists("hashCode", typeNode) == MemberExistsResult.NOT_EXISTS ) { JCMethodDecl method = createHashCode(typeNode, nodesForEquality); injectMethod(typeNode, method); } - if ( methodExists("toString", typeNode) == MethodExistsResult.NOT_EXISTS ) { + if ( methodExists("toString", typeNode) == MemberExistsResult.NOT_EXISTS ) { JCMethodDecl method = createToString(typeNode, nodesForEquality); injectMethod(typeNode, method); } diff --git a/src/lombok/javac/handlers/HandleSynchronized.java b/src/lombok/javac/handlers/HandleSynchronized.java new file mode 100644 index 00000000..4acb6e27 --- /dev/null +++ b/src/lombok/javac/handlers/HandleSynchronized.java @@ -0,0 +1,69 @@ +package lombok.javac.handlers; + +import static lombok.javac.handlers.PKG.*; + +import org.mangosdk.spi.ProviderFor; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.TypeTags; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.List; + +import lombok.Synchronized; +import lombok.core.AnnotationValues; +import lombok.core.AST.Kind; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacAST.Node; + +@ProviderFor(JavacAnnotationHandler.class) +public class HandleSynchronized implements JavacAnnotationHandler<Synchronized> { + private static final String INSTANCE_LOCK_NAME = "$lock"; + private static final String STATIC_LOCK_NAME = "$LOCK"; + + @Override public boolean handle(AnnotationValues<Synchronized> annotation, JCAnnotation ast, Node annotationNode) { + Node methodNode = annotationNode.up(); + + if ( methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl) ) { + annotationNode.addError("@Synchronized is legal only on methods."); + return true; + } + + JCMethodDecl method = (JCMethodDecl)methodNode.get(); + + if ( (method.mods.flags & Flags.ABSTRACT) != 0 ) { + annotationNode.addError("@Synchronized is legal only on concrete methods."); + return true; + } + boolean isStatic = (method.mods.flags & Flags.STATIC) != 0; + String lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; + + TreeMaker maker = methodNode.getTreeMaker(); + + if ( fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS ) { + JCExpression objectType = chainDots(maker, methodNode, "java", "lang", "Object"); + //We use 'new Object[0];' because quite unlike 'new Object();', empty arrays *ARE* serializable! + JCNewArray newObjectArray = maker.NewArray(chainDots(maker, methodNode, "java", "lang", "Object"), + List.<JCExpression>of(maker.Literal(TypeTags.INT, 0)), null); + JCVariableDecl fieldDecl = maker.VarDef( + maker.Modifiers(Flags.FINAL | (isStatic ? Flags.STATIC : 0)), + methodNode.toName(lockName), objectType, newObjectArray); + injectField(methodNode.up(), fieldDecl); + } + + if ( method.body == null ) return false; + + JCExpression lockNode = maker.Ident(methodNode.toName(lockName)); + + method.body = maker.Block(0, List.<JCStatement>of(maker.Synchronized(lockNode, method.body))); + + methodNode.rebuild(); + + return true; + } +} diff --git a/src/lombok/javac/handlers/PKG.java b/src/lombok/javac/handlers/PKG.java index 76bdd527..b7a02985 100644 --- a/src/lombok/javac/handlers/PKG.java +++ b/src/lombok/javac/handlers/PKG.java @@ -33,11 +33,31 @@ class PKG { return TransformationsUtil.toSetterName(fieldName); } - enum MethodExistsResult { + enum MemberExistsResult { NOT_EXISTS, EXISTS_BY_USER, EXISTS_BY_LOMBOK; } - static MethodExistsResult methodExists(String methodName, JavacAST.Node node) { + static MemberExistsResult fieldExists(String fieldName, JavacAST.Node node) { + while ( node != null && !(node.get() instanceof JCClassDecl) ) { + node = node.up(); + } + + if ( node != null && node.get() instanceof JCClassDecl ) { + for ( JCTree def : ((JCClassDecl)node.get()).defs ) { + if ( def instanceof JCVariableDecl ) { + if ( ((JCVariableDecl)def).name.contentEquals(fieldName) ) { + JavacAST.Node existing = node.getNodeFor(def); + if ( existing == null || !existing.isHandled() ) return MemberExistsResult.EXISTS_BY_USER; + return MemberExistsResult.EXISTS_BY_LOMBOK; + } + } + } + } + + return MemberExistsResult.NOT_EXISTS; + } + + static MemberExistsResult methodExists(String methodName, JavacAST.Node node) { while ( node != null && !(node.get() instanceof JCClassDecl) ) { node = node.up(); } @@ -47,17 +67,17 @@ class PKG { if ( def instanceof JCMethodDecl ) { if ( ((JCMethodDecl)def).name.contentEquals(methodName) ) { JavacAST.Node existing = node.getNodeFor(def); - if ( existing == null || !existing.isHandled() ) return MethodExistsResult.EXISTS_BY_USER; - return MethodExistsResult.EXISTS_BY_LOMBOK; + if ( existing == null || !existing.isHandled() ) return MemberExistsResult.EXISTS_BY_USER; + return MemberExistsResult.EXISTS_BY_LOMBOK; } } } } - return MethodExistsResult.NOT_EXISTS; + return MemberExistsResult.NOT_EXISTS; } - static MethodExistsResult constructorExists(JavacAST.Node node) { + static MemberExistsResult constructorExists(JavacAST.Node node) { while ( node != null && !(node.get() instanceof JCClassDecl) ) { node = node.up(); } @@ -68,14 +88,14 @@ class PKG { if ( ((JCMethodDecl)def).name.contentEquals("<init>") ) { if ( (((JCMethodDecl)def).mods.flags & Flags.GENERATEDCONSTR) != 0 ) continue; JavacAST.Node existing = node.getNodeFor(def); - if ( existing == null || !existing.isHandled() ) return MethodExistsResult.EXISTS_BY_USER; - return MethodExistsResult.EXISTS_BY_LOMBOK; + if ( existing == null || !existing.isHandled() ) return MemberExistsResult.EXISTS_BY_USER; + return MemberExistsResult.EXISTS_BY_LOMBOK; } } } } - return MethodExistsResult.NOT_EXISTS; + return MemberExistsResult.NOT_EXISTS; } static int toJavacModifier(AccessLevel accessLevel) { @@ -93,6 +113,14 @@ class PKG { } } + static void injectField(JavacAST.Node typeNode, JCVariableDecl field) { + JCClassDecl type = (JCClassDecl) typeNode.get(); + + type.defs = type.defs.append(field); + + typeNode.add(field, Kind.FIELD).recursiveSetHandled(); + } + static void injectMethod(JavacAST.Node typeNode, JCMethodDecl method) { JCClassDecl type = (JCClassDecl) typeNode.get(); |