aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/javac/handlers
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2010-11-09 20:37:25 +0100
committerReinier Zwitserloot <reinier@zwitserloot.com>2010-11-09 20:37:25 +0100
commit46d471e9c3dc32b03c34804df1819739a4dffc50 (patch)
tree9c31d75426bf8fdb1943bef2a996485640f7bf5e /src/core/lombok/javac/handlers
parent92b7efac48c18f22b81098cf1d844a891bb71648 (diff)
parent98d8a9f63b3183005174abb7691a1692347b9a2e (diff)
downloadlombok-46d471e9c3dc32b03c34804df1819739a4dffc50.tar.gz
lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.tar.bz2
lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.zip
Merge branch 'master' into annoGetSet
Diffstat (limited to 'src/core/lombok/javac/handlers')
-rw-r--r--src/core/lombok/javac/handlers/HandleCleanup.java16
-rw-r--r--src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java86
-rw-r--r--src/core/lombok/javac/handlers/HandleLog.java203
-rw-r--r--src/core/lombok/javac/handlers/HandleSynchronized.java2
-rw-r--r--src/core/lombok/javac/handlers/HandleVal.java113
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java30
6 files changed, 419 insertions, 31 deletions
diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java
index 2c89d9ad..779dd3ea 100644
--- a/src/core/lombok/javac/handlers/HandleCleanup.java
+++ b/src/core/lombok/javac/handlers/HandleCleanup.java
@@ -30,10 +30,12 @@ import lombok.javac.JavacNode;
import org.mangosdk.spi.ProviderFor;
+import com.sun.tools.javac.code.TypeTags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCatch;
@@ -41,6 +43,7 @@ import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
@@ -108,11 +111,16 @@ public class HandleCleanup implements JavacAnnotationHandler<Cleanup> {
doAssignmentCheck(annotationNode, tryBlock, decl.name);
TreeMaker maker = annotationNode.getTreeMaker();
- JCFieldAccess cleanupCall = maker.Select(maker.Ident(decl.name), annotationNode.toName(cleanupName));
- List<JCStatement> finalizerBlock = List.<JCStatement>of(maker.Exec(
- maker.Apply(List.<JCExpression>nil(), cleanupCall, List.<JCExpression>nil())));
+ JCFieldAccess cleanupMethod = maker.Select(maker.Ident(decl.name), annotationNode.toName(cleanupName));
+ List<JCStatement> cleanupCall = List.<JCStatement>of(maker.Exec(
+ maker.Apply(List.<JCExpression>nil(), cleanupMethod, List.<JCExpression>nil())));
+
+ JCBinary isNull = maker.Binary(JCTree.NE, maker.Ident(decl.name), maker.Literal(TypeTags.BOT, null));
+
+ JCIf ifNotNullCleanup = maker.If(isNull, maker.Block(0, cleanupCall), null);
+
+ JCBlock finalizer = maker.Block(0, List.<JCStatement>of(ifNotNullCleanup));
- JCBlock finalizer = maker.Block(0, finalizerBlock);
newStatements = newStatements.append(maker.Try(maker.Block(0, tryBlock), List.<JCCatch>nil(), finalizer));
if (blockNode instanceof JCBlock) {
diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
index ee049f1f..c5475fb1 100644
--- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
@@ -167,9 +167,13 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
}
}
+ boolean needsCanEqual = false;
switch (methodExists("equals", typeNode)) {
case NOT_EXISTS:
- JCMethodDecl method = createEquals(typeNode, nodesForEquality, callSuper, useFieldsDirectly);
+ boolean isFinal = (((JCClassDecl)typeNode.get()).mods.flags & Flags.FINAL) != 0;
+ needsCanEqual = !isFinal || !isDirectDescendantOfObject;
+
+ JCMethodDecl method = createEquals(typeNode, nodesForEquality, callSuper, useFieldsDirectly, needsCanEqual);
injectMethod(typeNode, method);
break;
case EXISTS_BY_LOMBOK:
@@ -182,6 +186,18 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
break;
}
+ if (needsCanEqual) {
+ switch (methodExists("canEqual", typeNode)) {
+ case NOT_EXISTS:
+ JCMethodDecl method = createCanEqual(typeNode);
+ injectMethod(typeNode, method);
+ break;
+ case EXISTS_BY_LOMBOK:
+ case EXISTS_BY_USER:
+ default:
+ break;
+ }
+ }
switch (methodExists("hashCode", typeNode)) {
case NOT_EXISTS:
JCMethodDecl method = createHashCode(typeNode, nodesForEquality, callSuper, useFieldsDirectly);
@@ -196,7 +212,6 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
}
break;
}
-
return true;
}
@@ -314,7 +329,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
return maker.TypeCast(maker.TypeIdent(TypeTags.INT), xorBits);
}
- private JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, boolean useFieldsDirectly) {
+ private JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, boolean useFieldsDirectly, boolean needsCanEqual) {
TreeMaker maker = typeNode.getTreeMaker();
JCClassDecl type = (JCClassDecl) typeNode.get();
@@ -335,27 +350,9 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
maker.Ident(thisName)), returnBool(maker, true), null));
}
- /* if (o == null) return false; */ {
- statements = statements.append(maker.If(maker.Binary(JCTree.EQ, maker.Ident(oName),
- maker.Literal(TypeTags.BOT, null)), returnBool(maker, false), null));
- }
-
- /* if (o.getClass() != this.getClass()) return false; */ {
- Name getClass = typeNode.toName("getClass");
- List<JCExpression> exprNil = List.nil();
- JCExpression oGetClass = maker.Apply(exprNil, maker.Select(maker.Ident(oName), getClass), exprNil);
- JCExpression thisGetClass = maker.Apply(exprNil, maker.Select(maker.Ident(thisName), getClass), exprNil);
- statements = statements.append(
- maker.If(maker.Binary(JCTree.NE, oGetClass, thisGetClass), returnBool(maker, false), null));
- }
-
- /* if (!super.equals(o)) return false; */
- if (callSuper) {
- JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
- maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")),
- List.<JCExpression>of(maker.Ident(oName)));
- JCUnary superNotEqual = maker.Unary(JCTree.NOT, callToSuper);
- statements = statements.append(maker.If(superNotEqual, returnBool(maker, false), null));
+ /* if (!(o instanceof MyType) return false; */ {
+ JCUnary notInstanceOf = maker.Unary(JCTree.NOT, maker.TypeTest(maker.Ident(oName), maker.Ident(type.name)));
+ statements = statements.append(maker.If(notInstanceOf, returnBool(maker, false), null));
}
/* MyType<?> other = (MyType<?>) o; */ {
@@ -379,6 +376,25 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
maker.VarDef(maker.Modifiers(Flags.FINAL), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName))));
}
+ /* if (!other.canEqual(this)) return false; */ {
+ if (needsCanEqual) {
+ List<JCExpression> exprNil = List.nil();
+ JCExpression equalityCheck = maker.Apply(exprNil,
+ maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")),
+ List.<JCExpression>of(maker.Ident(thisName)));
+ statements = statements.append(maker.If(maker.Unary(JCTree.NOT, equalityCheck), returnBool(maker, false), null));
+ }
+ }
+
+ /* if (!super.equals(o)) return false; */
+ if (callSuper) {
+ JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
+ maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")),
+ List.<JCExpression>of(maker.Ident(oName)));
+ JCUnary superNotEqual = maker.Unary(JCTree.NOT, callToSuper);
+ statements = statements.append(maker.If(superNotEqual, returnBool(maker, false), null));
+ }
+
for (JavacNode fieldNode : fields) {
JCExpression fType = getFieldType(fieldNode, useFieldsDirectly);
JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, useFieldsDirectly);
@@ -428,6 +444,27 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
JCBlock body = maker.Block(0, statements);
return maker.MethodDef(mods, typeNode.toName("equals"), returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null);
}
+
+ private JCMethodDecl createCanEqual(JavacNode typeNode) {
+ /* public boolean canEquals(final java.lang.Object other) {
+ * return other instanceof MyType;
+ * }
+ */
+ TreeMaker maker = typeNode.getTreeMaker();
+ JCClassDecl type = (JCClassDecl) typeNode.get();
+
+ JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.<JCAnnotation>nil());
+ JCExpression returnType = maker.TypeIdent(TypeTags.BOOLEAN);
+ Name canEqualName = typeNode.toName("canEqual");
+ JCExpression objectType = chainDots(maker, typeNode, "java", "lang", "Object");
+ Name otherName = typeNode.toName("other");
+ List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(Flags.FINAL), otherName, objectType, null));
+
+ JCBlock body = maker.Block(0, List.<JCStatement>of(
+ maker.Return(maker.TypeTest(maker.Ident(otherName), maker.Ident(type.name)))));
+
+ return maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null);
+ }
private JCStatement generateCompareFloatOrDouble(JCExpression thisDotField, JCExpression otherDotField,
TreeMaker maker, JavacNode node, boolean isDouble) {
@@ -442,5 +479,4 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
private JCStatement returnBool(TreeMaker maker, boolean bool) {
return maker.Return(maker.Literal(TypeTags.BOOLEAN, bool ? 1 : 0));
}
-
}
diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java
new file mode 100644
index 00000000..03e40d7f
--- /dev/null
+++ b/src/core/lombok/javac/handlers/HandleLog.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2010 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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.javac.handlers;
+
+import static lombok.javac.handlers.JavacHandlerUtil.*;
+
+import java.lang.annotation.Annotation;
+
+import lombok.core.AnnotationValues;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacNode;
+import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;
+
+import org.mangosdk.spi.ProviderFor;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+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.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+
+public class HandleLog {
+
+ private HandleLog() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static boolean processAnnotation(LoggingFramework framework, AnnotationValues<?> annotation, JavacNode annotationNode) {
+ markAnnotationAsProcessed(annotationNode, framework.getAnnotationClass());
+
+// String loggingClassName = annotation.getRawExpression("value");
+// if (loggingClassName == null) loggingClassName = "void";
+// if (loggingClassName.endsWith(".class")) loggingClassName = loggingClassName.substring(0, loggingClassName.length() - 6);
+
+ JCExpression annotationValue = (JCExpression) annotation.getActualExpression("value");
+ JCFieldAccess loggingType = null;
+ if (annotationValue != null) {
+ if (!(annotationValue instanceof JCFieldAccess)) return true;
+ loggingType = (JCFieldAccess) annotationValue;
+ if (!loggingType.name.contentEquals("class")) return true;
+ }
+
+
+ JavacNode typeNode = annotationNode.up();
+ switch (typeNode.getKind()) {
+ case TYPE:
+ if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE)!= 0) {
+ annotationNode.addError("@Log is legal only on classes and enums.");
+ return true;
+ }
+
+ if (fieldExists("log", typeNode)!= MemberExistsResult.NOT_EXISTS) {
+ annotationNode.addWarning("Field 'log' already exists.");
+ return true;
+ }
+
+ if (loggingType == null) {
+ loggingType = selfType(typeNode);
+ }
+ createField(framework, typeNode, loggingType);
+ return true;
+ default:
+ annotationNode.addError("@Log is legal only on types.");
+ return true;
+ }
+ }
+
+ private static JCFieldAccess selfType(JavacNode typeNode) {
+ TreeMaker maker = typeNode.getTreeMaker();
+ Name name = ((JCClassDecl) typeNode.get()).name;
+ return maker.Select(maker.Ident(name), typeNode.toName("class"));
+ }
+
+ private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType) {
+ TreeMaker maker = typeNode.getTreeMaker();
+
+ // private static final <loggerType> log = <factoryMethod>(<parameter>);
+ JCExpression loggerType = chainDotsString(maker, typeNode, framework.getLoggerTypeName());
+ JCExpression factoryMethod = chainDotsString(maker, typeNode, framework.getLoggerFactoryMethodName());
+
+ JCExpression loggerName = framework.createFactoryParameter(typeNode, loggingType);
+ JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName));
+
+ JCVariableDecl fieldDecl = maker.VarDef(
+ maker.Modifiers(Flags.PRIVATE | Flags.FINAL | Flags.STATIC),
+ typeNode.toName("log"), loggerType, factoryMethodCall);
+
+ injectField(typeNode, fieldDecl);
+ return true;
+ }
+
+ /**
+ * Handles the {@link lombok.extern.apachecommons.Log} annotation for javac.
+ */
+ @ProviderFor(JavacAnnotationHandler.class)
+ public static class HandleCommonsLog implements JavacAnnotationHandler<lombok.extern.apachecommons.Log> {
+ @Override public boolean handle(AnnotationValues<lombok.extern.apachecommons.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ return processAnnotation(LoggingFramework.COMMONS, annotation, annotationNode);
+ }
+ }
+
+ /**
+ * Handles the {@link lombok.extern.jul.Log} annotation for javac.
+ */
+ @ProviderFor(JavacAnnotationHandler.class)
+ public static class HandleJulLog implements JavacAnnotationHandler<lombok.extern.jul.Log> {
+ @Override public boolean handle(AnnotationValues<lombok.extern.jul.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ return processAnnotation(LoggingFramework.JUL, annotation, annotationNode);
+ }
+ }
+
+ /**
+ * Handles the {@link lombok.extern.log4j.Log} annotation for javac.
+ */
+ @ProviderFor(JavacAnnotationHandler.class)
+ public static class HandleLog4jLog implements JavacAnnotationHandler<lombok.extern.log4j.Log> {
+ @Override public boolean handle(AnnotationValues<lombok.extern.log4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ return processAnnotation(LoggingFramework.LOG4J, annotation, annotationNode);
+ }
+ }
+
+ /**
+ * Handles the {@link lombok.extern.slf4j.Log} annotation for javac.
+ */
+ @ProviderFor(JavacAnnotationHandler.class)
+ public static class HandleSlf4jLog implements JavacAnnotationHandler<lombok.extern.slf4j.Log> {
+ @Override public boolean handle(AnnotationValues<lombok.extern.slf4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ return processAnnotation(LoggingFramework.SLF4J, annotation, annotationNode);
+ }
+ }
+
+ enum LoggingFramework {
+ // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class);
+ COMMONS(lombok.extern.jul.Log.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory.getLog"),
+
+ // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName());
+ JUL(lombok.extern.jul.Log.class, "java.util.logging.Logger", "java.util.logging.Logger.getLogger") {
+ @Override public JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) {
+ TreeMaker maker = typeNode.getTreeMaker();
+ JCExpression method = maker.Select(loggingType, typeNode.toName("getName"));
+ return maker.Apply(List.<JCExpression>nil(), method, List.<JCExpression>nil());
+ }
+ },
+
+ // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class);
+ LOG4J(lombok.extern.jul.Log.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger.getLogger"),
+
+ // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class);
+ SLF4J(lombok.extern.slf4j.Log.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory.getLogger"),
+
+ ;
+
+ private final Class<? extends Annotation> annotationClass;
+ private final String loggerTypeName;
+ private final String loggerFactoryName;
+
+ LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName) {
+ this.annotationClass = annotationClass;
+ this.loggerTypeName = loggerTypeName;
+ this.loggerFactoryName = loggerFactoryName;
+ }
+
+ final Class<? extends Annotation> getAnnotationClass() {
+ return annotationClass;
+ }
+
+ final String getLoggerTypeName() {
+ return loggerTypeName;
+ }
+
+ final String getLoggerFactoryMethodName() {
+ return loggerFactoryName;
+ }
+
+ JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) {
+ return loggingType;
+ }
+ }
+}
diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java
index 2f900eb8..a095aaf1 100644
--- a/src/core/lombok/javac/handlers/HandleSynchronized.java
+++ b/src/core/lombok/javac/handlers/HandleSynchronized.java
@@ -89,7 +89,7 @@ public class HandleSynchronized implements JavacAnnotationHandler<Synchronized>
JCVariableDecl fieldDecl = maker.VarDef(
maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (isStatic ? Flags.STATIC : 0)),
methodNode.toName(lockName), objectType, newObjectArray);
- injectField(methodNode.up(), fieldDecl);
+ injectFieldSuppressWarnings(methodNode.up(), fieldDecl);
}
if (method.body == null) return false;
diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java
new file mode 100644
index 00000000..5da6fec0
--- /dev/null
+++ b/src/core/lombok/javac/handlers/HandleVal.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright © 2010 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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.javac.handlers;
+
+import lombok.javac.JavacASTAdapter;
+import lombok.javac.JavacASTVisitor;
+import lombok.javac.JavacNode;
+import lombok.javac.JavacResolution;
+
+import org.mangosdk.spi.ProviderFor;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCNewArray;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+
+@ProviderFor(JavacASTVisitor.class)
+public class HandleVal extends JavacASTAdapter {
+ @Override public boolean isResolutionBased() {
+ return true;
+ }
+
+ @Override public void visitLocal(JavacNode localNode, JCVariableDecl local) {
+ if (local.vartype != null && local.vartype.toString().equals("val")) {
+ JCExpression rhsOfEnhancedForLoop = null;
+ if (local.init == null) {
+ JCTree parentRaw = localNode.directUp().get();
+ if (parentRaw instanceof JCEnhancedForLoop) {
+ JCEnhancedForLoop efl = (JCEnhancedForLoop) parentRaw;
+ if (efl.var == local) rhsOfEnhancedForLoop = efl.expr;
+ }
+ }
+
+ if (rhsOfEnhancedForLoop == null && local.init == null) {
+ localNode.addError("'val' on a local variable requires an initializer expression");
+ return;
+ }
+
+ if (local.init instanceof JCNewArray && ((JCNewArray)local.init).elemtype == null) {
+ localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })");
+ return;
+ }
+
+ local.mods.flags |= Flags.FINAL;
+ local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());
+
+ Type type;
+ try {
+ if (rhsOfEnhancedForLoop == null) {
+ if (local.init.type == null) {
+ JavacResolution resolver = new JavacResolution(localNode.getContext());
+ type = ((JCExpression) resolver.resolve(localNode).get(local.init)).type;
+ } else {
+ type = local.init.type;
+ }
+ } else {
+ if (rhsOfEnhancedForLoop.type == null) {
+ JavacResolution resolver = new JavacResolution(localNode.getContext());
+ type = ((JCExpression) resolver.resolve(localNode.directUp()).get(rhsOfEnhancedForLoop)).type;
+ } else {
+ type = rhsOfEnhancedForLoop.type;
+ }
+ }
+
+ try {
+ JCExpression replacement;
+
+ 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());
+ } else {
+ replacement = JavacResolution.typeToJCTree(type, localNode.getTreeMaker(), localNode.getAst());
+ }
+
+ if (replacement != null) {
+ local.vartype = replacement;
+ localNode.getAst().setChanged();
+ }
+ else local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());;
+ } 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());;
+ }
+ } catch (RuntimeException e) {
+ local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());;
+ throw e;
+ }
+ }
+ }
+}
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index 79436327..5dacf2ca 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -392,13 +392,26 @@ public class JavacHandlerUtil {
/**
* Adds the given new field declaration to the provided type AST Node.
+ * The field carries the &#64;{@link SuppressWarnings}("all") annotation.
+ * Also takes care of updating the JavacAST.
+ */
+ public static void injectFieldSuppressWarnings(JavacNode typeNode, JCVariableDecl field) {
+ injectField(typeNode, field, true);
+ }
+
+ /**
+ * Adds the given new field declaration to the provided type AST Node.
*
* Also takes care of updating the JavacAST.
*/
public static void injectField(JavacNode typeNode, JCVariableDecl field) {
+ injectField(typeNode, field, false);
+ }
+
+ private static void injectField(JavacNode typeNode, JCVariableDecl field, boolean addSuppressWarnings) {
JCClassDecl type = (JCClassDecl) typeNode.get();
- addSuppressWarningsAll(field.mods, typeNode, field.pos);
+ if (addSuppressWarnings) addSuppressWarningsAll(field.mods, typeNode, field.pos);
type.defs = type.defs.append(field);
typeNode.add(field, Kind.FIELD).recursiveSetHandled();
@@ -476,6 +489,21 @@ public class JavacHandlerUtil {
return e;
}
+
+
+ /**
+ * 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.
+ *
+ * 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 chainDotsString(TreeMaker maker, JavacNode node, String elems) {
+ return chainDots(maker, node, elems.split("\\."));
+ }
/**
* Searches the given field node for annotations and returns each one that matches the provided regular expression pattern.