diff options
Diffstat (limited to 'src/core/lombok/javac')
-rw-r--r-- | src/core/lombok/javac/JavacAST.java | 28 | ||||
-rw-r--r-- | src/core/lombok/javac/apt/LombokProcessor.java | 41 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleNonNull.java | 39 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleVal.java | 24 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 82 |
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; } |