mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 14:17:48 +00:00
Added @Synchronized support to javac. Seems to work well.
This commit is contained in:
1 parent
34780e3ab5
commit
194c990f64
4 files changed
+112
-14
No files matched your search
@@ -82,6 +82,7 @@ public class HandleSynchronized implements EclipseAnnotationHandler<Synchronized
|
||||
};
|
||||
|
||||
methodNode.rebuild();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in new issue
Block a user