aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/javac
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lombok/javac')
-rw-r--r--src/core/lombok/javac/JavacAST.java28
-rw-r--r--src/core/lombok/javac/apt/LombokProcessor.java41
-rw-r--r--src/core/lombok/javac/handlers/HandleNonNull.java39
-rw-r--r--src/core/lombok/javac/handlers/HandleVal.java24
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java82
5 files changed, 140 insertions, 74 deletions
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index 0919c7d4..c09120c1 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -36,7 +36,6 @@ import javax.annotation.processing.Messager;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
-import com.sun.tools.javac.util.JCDiagnostic;
import lombok.core.AST;
import lombok.core.CleanupRegistry;
import lombok.core.CleanupTask;
@@ -53,6 +52,7 @@ import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
@@ -63,6 +63,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
@@ -415,6 +416,18 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
JCANNOTATEDTYPE_FIELDS_INITIALIZED = true;
}
+
+ private static Field JCENHANCEDFORLOOP_VARORRECORDPATTERN_FIELD = Permit.permissiveGetField(JCEnhancedForLoop.class, "varOrRecordPattern");
+ private static JCTree getVarOrRecordPattern(JCEnhancedForLoop loop) {
+ if (JCENHANCEDFORLOOP_VARORRECORDPATTERN_FIELD == null) {
+ return loop.var;
+ }
+ try {
+ return (JCTree) JCENHANCEDFORLOOP_VARORRECORDPATTERN_FIELD.get(loop);
+ } catch (Exception ignore) {}
+ return null;
+ }
+
private JavacNode buildTry(JCTry tryNode) {
if (setAndGetAsHandled(tryNode)) return null;
List<JavacNode> childNodes = new ArrayList<JavacNode>();
@@ -471,6 +484,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
if (statement instanceof JCVariableDecl) return buildLocalVar((JCVariableDecl) statement, Kind.LOCAL);
if (statement instanceof JCTry) return buildTry((JCTry) statement);
if (statement.getClass().getName().equals("com.sun.tools.javac.tree.JCTree$JCLambda")) return buildLambda(statement);
+ if (statement instanceof JCEnhancedForLoop) return buildEnhancedForLoop((JCEnhancedForLoop) statement);
if (setAndGetAsHandled(statement)) return null;
return drill(statement);
@@ -500,6 +514,18 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
return getBodyMethods.get(c);
}
+ private JavacNode buildEnhancedForLoop(JCEnhancedForLoop loop) {
+ if (setAndGetAsHandled(loop)) return null;
+
+ List<JavacNode> childNodes = new ArrayList<JavacNode>();
+ // The order of the child elements is important and must be kept
+ addIfNotNull(childNodes, buildTree(getVarOrRecordPattern(loop), Kind.STATEMENT));
+ addIfNotNull(childNodes, buildTree(loop.expr, Kind.STATEMENT));
+ addIfNotNull(childNodes, buildStatement(loop.body));
+
+ return putInMap(new JavacNode(this, loop, childNodes, Kind.STATEMENT));
+ }
+
private JavacNode drill(JCTree statement) {
try {
List<JavacNode> childNodes = new ArrayList<JavacNode>();
diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java
index ed713b1d..0467d758 100644
--- a/src/core/lombok/javac/apt/LombokProcessor.java
+++ b/src/core/lombok/javac/apt/LombokProcessor.java
@@ -25,7 +25,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
@@ -305,10 +304,7 @@ public class LombokProcessor extends AbstractProcessor {
// Step 1: Take all CUs which aren't already in the map. Give them the first priority level.
- String randomModuleName = null;
-
for (Element element : roundEnv.getRootElements()) {
- if (randomModuleName == null) randomModuleName = getModuleNameFor(element);
JCCompilationUnit unit = toUnit(element);
if (unit == null) continue;
if (roots.containsKey(unit)) continue;
@@ -353,7 +349,7 @@ public class LombokProcessor extends AbstractProcessor {
newLevels.retainAll(priorityLevelsRequiringResolutionReset);
if (!newLevels.isEmpty()) {
// Force a new round to reset resolution. The next round will cause this method (process) to be called again.
- forceNewRound(randomModuleName, javacFiler);
+ forceNewRound(javacFiler);
return false;
}
// None of the new levels need resolution, so just keep going.
@@ -361,7 +357,7 @@ public class LombokProcessor extends AbstractProcessor {
}
private int dummyCount = 0;
- private void forceNewRound(String randomModuleName, JavacFiler filer) {
+ private void forceNewRound(JavacFiler filer) {
if (!filer.newFiles()) {
try {
filer.getGeneratedSourceNames().add("lombok.dummy.ForceNewRound" + (dummyCount++));
@@ -372,38 +368,7 @@ public class LombokProcessor extends AbstractProcessor {
}
}
}
-
- private String getModuleNameFor(Element element) {
- while (element != null) {
- if (element.getKind().name().equals("MODULE")) return getModuleName(element);
- Element n = element.getEnclosingElement();
- if (n == element) return null;
- element = n;
- }
- return null;
- }
-
- private static Class<?> qualifiedNamableClass = null;
- private static Method qualifiedNamableQualifiedNameMethod = null;
- // QualifiedNameable isn't in java 6, so to remain compatible with java6, use reflection.
- private static String getModuleName(Element element) {
- try {
- if (qualifiedNamableClass == null) qualifiedNamableClass = Class.forName("javax.lang.model.element.QualifiedNamable");
- if (!qualifiedNamableClass.isInstance(element)) return null;
- if (qualifiedNamableQualifiedNameMethod == null) qualifiedNamableQualifiedNameMethod = Permit.getMethod(qualifiedNamableClass, "getQualifiedName");
- String name = Permit.invoke(qualifiedNamableQualifiedNameMethod, element).toString().trim();
- return name.isEmpty() ? null : name;
- } catch (ClassNotFoundException e) {
- return null;
- } catch (NoSuchMethodException e) {
- return null;
- } catch (InvocationTargetException e) {
- return null;
- } catch (IllegalAccessException e) {
- return null;
- }
- }
-
+
private JCCompilationUnit toUnit(Element element) {
TreePath path = null;
if (trees != null) {
diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java
index 271bedbb..e817916d 100644
--- a/src/core/lombok/javac/handlers/HandleNonNull.java
+++ b/src/core/lombok/javac/handlers/HandleNonNull.java
@@ -218,48 +218,43 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
@Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull");
- if (annotationNode.up().getKind() == Kind.FIELD) {
+
+ final JavacNode node;
+ if (annotationNode.up().getKind() == Kind.TYPE_USE) {
+ node = annotationNode.directUp().directUp();
+ } else {
+ node = annotationNode.up();
+ }
+
+ if (node.getKind() == Kind.FIELD) {
// This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc),
// but in that case those handlers will take care of it. However, we DO check if the annotation is applied to
// a primitive, because those handlers trigger on any annotation named @NonNull and we only want the warning
// behaviour on _OUR_ 'lombok.NonNull'.
try {
- if (isPrimitive(((JCVariableDecl) annotationNode.up().get()).vartype)) {
+ if (isPrimitive(((JCVariableDecl) node.get()).vartype)) {
annotationNode.addWarning("@NonNull is meaningless on a primitive.");
}
} catch (Exception ignore) {}
- JCVariableDecl fDecl = (JCVariableDecl) annotationNode.up().get();
+ JCVariableDecl fDecl = (JCVariableDecl) node.get();
if ((fDecl.mods.flags & RECORD) != 0) {
// well, these kinda double as parameters (of the compact constructor), so we do some work here.
- List<JCMethodDecl> compactConstructors = addCompactConstructorIfNeeded(annotationNode.up().up(), annotationNode);
+ List<JCMethodDecl> compactConstructors = addCompactConstructorIfNeeded(node.up(), annotationNode);
for (JCMethodDecl ctr : compactConstructors) {
- addNullCheckIfNeeded(ctr, annotationNode.up(), annotationNode);
+ addNullCheckIfNeeded(ctr, node, annotationNode);
}
}
return;
}
- JCMethodDecl declaration;
- JavacNode paramNode;
+ if (node.getKind() != Kind.ARGUMENT) return;
- switch (annotationNode.up().getKind()) {
- case ARGUMENT:
- paramNode = annotationNode.up();
- break;
- case TYPE_USE:
- JavacNode typeNode = annotationNode.directUp();
- paramNode = typeNode.directUp();
- break;
- default:
- return;
- }
-
- if (paramNode.getKind() != Kind.ARGUMENT) return;
+ JCMethodDecl declaration;
try {
- declaration = (JCMethodDecl) paramNode.up().get();
+ declaration = (JCMethodDecl) node.up().get();
} catch (Exception e) {
return;
}
@@ -276,7 +271,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
return;
}
- addNullCheckIfNeeded(declaration, paramNode, annotationNode);
+ addNullCheckIfNeeded(declaration, node, annotationNode);
}
public boolean isNullCheck(JCStatement stat) {
diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java
index d4fb1027..8f4b1a86 100644
--- a/src/core/lombok/javac/handlers/HandleVal.java
+++ b/src/core/lombok/javac/handlers/HandleVal.java
@@ -24,15 +24,19 @@ package lombok.javac.handlers;
import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
import static lombok.javac.handlers.HandleDelegate.HANDLE_DELEGATE_PRIORITY;
import static lombok.javac.handlers.JavacHandlerUtil.*;
+
+import java.lang.reflect.Field;
+
import lombok.ConfigurationKeys;
import lombok.val;
-import lombok.core.HandlerPriority;
import lombok.var;
+import lombok.core.HandlerPriority;
import lombok.javac.JavacASTAdapter;
import lombok.javac.JavacASTVisitor;
import lombok.javac.JavacNode;
import lombok.javac.JavacResolution;
import lombok.javac.ResolutionResetNeeded;
+import lombok.permit.Permit;
import lombok.spi.Provides;
import com.sun.tools.javac.code.Flags;
@@ -87,7 +91,8 @@ public class HandleVal extends JavacASTAdapter {
if (local.init == null) {
if (parentRaw instanceof JCEnhancedForLoop) {
JCEnhancedForLoop efl = (JCEnhancedForLoop) parentRaw;
- if (efl.var == local) rhsOfEnhancedForLoop = efl.expr;
+ JCTree var = EnhancedForLoopReflect.getVarOrRecordPattern(efl);
+ if (var == local) rhsOfEnhancedForLoop = efl.expr;
}
}
@@ -191,4 +196,19 @@ public class HandleVal extends JavacASTAdapter {
recursiveSetGeneratedBy(local.vartype, typeNode);
}
}
+
+ private static class EnhancedForLoopReflect {
+ private static final Field varOrRecordPattern = Permit.permissiveGetField(JCEnhancedForLoop.class, "varOrRecordPattern");
+
+ private static JCTree getVarOrRecordPattern(JCEnhancedForLoop loop) {
+ if (varOrRecordPattern == null) {
+ return loop.var;
+ }
+
+ try {
+ return (JCTree) varOrRecordPattern.get(loop);
+ } catch (Exception ignore) {}
+ return null;
+ }
+ }
}
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index 9d153a72..ac947581 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -313,7 +313,11 @@ public class JavacHandlerUtil {
* @param typeNode A type reference to check.
*/
public static boolean typeMatches(String type, JavacNode node, JCTree typeNode) {
- String typeName = typeNode == null ? null : typeNode.toString();
+ String typeName = getTypeName(typeNode);
+ return typeMatches(type, node, typeName);
+ }
+
+ private static boolean typeMatches(String type, JavacNode node, String typeName) {
if (typeName == null || typeName.length() == 0) return false;
int lastIndexA = typeName.lastIndexOf('.') + 1;
int lastIndexB = Math.max(type.lastIndexOf('.'), type.lastIndexOf('$')) + 1;
@@ -323,7 +327,11 @@ public class JavacHandlerUtil {
TypeResolver resolver = node.getImportListAsTypeResolver();
return resolver.typeMatches(node, type, typeName);
}
-
+
+ private static String getTypeName(JCTree typeNode) {
+ return typeNode == null ? null : typeNode.toString();
+ }
+
/**
* Returns if a field is marked deprecated, either by {@code @Deprecated} or in javadoc
* @param field the field to check
@@ -512,6 +520,13 @@ public class JavacHandlerUtil {
case LOCAL:
JCVariableDecl variable = (JCVariableDecl) parentNode.get();
variable.mods.annotations = filterList(variable.mods.annotations, annotation.get());
+
+ if ((variable.mods.flags & GENERATED_MEMBER) != 0) {
+ JavacNode typeNode = upToTypeNode(annotation);
+ if (isRecord(typeNode)) {
+ RecordComponentReflect.deleteAnnotation((JCClassDecl) typeNode.get(), variable, annotation.get());
+ }
+ }
break;
case METHOD:
JCMethodDecl method = (JCMethodDecl) parentNode.get();
@@ -559,6 +574,47 @@ public class JavacHandlerUtil {
return newAnnotations.toList();
}
+ private static List<JCAnnotation> filterListByPos(List<JCAnnotation> annotations, JCTree jcTree) {
+ ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<JCAnnotation>();
+ for (JCAnnotation ann : annotations) {
+ if (jcTree.pos != ann.pos) newAnnotations.append(ann);
+ }
+ return newAnnotations.toList();
+ }
+
+
+ static class RecordComponentReflect {
+
+ private static final Field astField;
+ private static final Method findRecordComponentToRemove;
+
+ static {
+ Field a = null;
+ Method m = null;
+ try {
+ Class<?> forName = Class.forName("com.sun.tools.javac.code.Symbol$RecordComponent");
+ a = Permit.permissiveGetField(forName, "ast");
+ m = Permit.permissiveGetMethod(ClassSymbol.class, "findRecordComponentToRemove", JCVariableDecl.class);
+ } catch (Throwable e) {
+ // Ignore
+ }
+ astField = a;
+ findRecordComponentToRemove = m;
+ }
+
+ static void deleteAnnotation(JCClassDecl record, JCVariableDecl component, JCTree annotation) {
+ if (astField == null || findRecordComponentToRemove == null) return;
+
+ try {
+ Object toRemove = Permit.invokeSneaky(findRecordComponentToRemove, record.sym, component);
+ JCVariableDecl variable = (JCVariableDecl) Permit.get(astField, toRemove);
+ variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation);
+ } catch (Throwable e) {
+ // Ignore
+ }
+ }
+ }
+
/** Serves as return value for the methods that check for the existence of fields and methods. */
public enum MemberExistsResult {
NOT_EXISTS, EXISTS_BY_LOMBOK, EXISTS_BY_USER;
@@ -1617,7 +1673,8 @@ public class JavacHandlerUtil {
for (JavacNode child : node.down()) {
if (child.getKind() == Kind.ANNOTATION) {
JCAnnotation annotation = (JCAnnotation) child.get();
- for (String nn : NONNULL_ANNOTATIONS) if (typeMatches(nn, node, annotation.annotationType)) return true;
+ String annotationTypeName = getTypeName(annotation.annotationType);
+ for (String nn : NONNULL_ANNOTATIONS) if (typeMatches(nn, node, annotationTypeName)) return true;
}
}
@@ -1627,7 +1684,8 @@ public class JavacHandlerUtil {
public static boolean hasNonNullAnnotations(JavacNode node, List<JCAnnotation> anns) {
if (anns == null) return false;
for (JCAnnotation ann : anns) {
- for (String nn : NONNULL_ANNOTATIONS) if (typeMatches(nn, node, ann)) return true;
+ String annotationTypeName = getTypeName(ann.annotationType);
+ for (String nn : NONNULL_ANNOTATIONS) if (typeMatches(nn, node, annotationTypeName)) return true;
}
return false;
@@ -1656,21 +1714,22 @@ public class JavacHandlerUtil {
java.util.List<TypeName> configuredCopyable = node.getAst().readConfiguration(ConfigurationKeys.COPYABLE_ANNOTATIONS);
if (!annoName.isEmpty()) {
- for (TypeName cn : configuredCopyable) if (cn != null && typeMatches(cn.toString(), node, anno.annotationType)) return List.of(anno);
- for (String bn : BASE_COPYABLE_ANNOTATIONS) if (typeMatches(bn, node, anno.annotationType)) return List.of(anno);
+ for (TypeName cn : configuredCopyable) if (cn != null && typeMatches(cn.toString(), node, annoName)) return List.of(anno);
+ for (String bn : BASE_COPYABLE_ANNOTATIONS) if (typeMatches(bn, node, annoName)) return List.of(anno);
}
-
+
ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>();
for (JavacNode child : node.down()) {
if (child.getKind() == Kind.ANNOTATION) {
JCAnnotation annotation = (JCAnnotation) child.get();
+ String annotationTypeName = getTypeName(annotation.annotationType);
boolean match = false;
- for (TypeName cn : configuredCopyable) if (cn != null && typeMatches(cn.toString(), node, annotation.annotationType)) {
+ for (TypeName cn : configuredCopyable) if (cn != null && typeMatches(cn.toString(), node, annotationTypeName)) {
result.append(annotation);
match = true;
break;
}
- if (!match) for (String bn : BASE_COPYABLE_ANNOTATIONS) if (typeMatches(bn, node, annotation.annotationType)) {
+ if (!match) for (String bn : BASE_COPYABLE_ANNOTATIONS) if (typeMatches(bn, node, annotationTypeName)) {
result.append(annotation);
break;
}
@@ -1714,15 +1773,16 @@ public class JavacHandlerUtil {
if (annoName == null) return List.nil();
if (!annoName.isEmpty()) {
- for (String bn : annotationsToFind) if (typeMatches(bn, node, anno.annotationType)) return List.of(anno);
+ for (String bn : annotationsToFind) if (typeMatches(bn, node, annoName)) return List.of(anno);
}
ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>();
for (JavacNode child : node.down()) {
if (child.getKind() == Kind.ANNOTATION) {
JCAnnotation annotation = (JCAnnotation) child.get();
+ String annotationTypeName = getTypeName(annotation.annotationType);
boolean match = false;
- if (!match) for (String bn : annotationsToFind) if (typeMatches(bn, node, annotation.annotationType)) {
+ if (!match) for (String bn : annotationsToFind) if (typeMatches(bn, node, annotationTypeName)) {
result.append(annotation);
break;
}