From b867f81b8a251a8a32e42f53c2be34d520938bd7 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 13 Dec 2016 00:52:32 +0100 Subject: Lombok will now also fix the typemirror info when generating bean-related methods/constructors, to allow other annotation processors to see these generated methods/constructors too. --- src/core/lombok/javac/HandlerLibrary.java | 13 +++--- src/core/lombok/javac/JavacAST.java | 2 +- src/core/lombok/javac/JavacASTAdapter.java | 4 ++ src/core/lombok/javac/JavacASTVisitor.java | 5 +++ src/core/lombok/javac/JavacAnnotationHandler.java | 7 ++++ src/core/lombok/javac/JavacNode.java | 10 ++++- src/core/lombok/javac/JavacTransformer.java | 9 ++-- src/core/lombok/javac/apt/LombokProcessor.java | 49 ++++++++++++++++++++-- src/core/lombok/javac/handlers/HandleGetter.java | 5 ++- src/core/lombok/javac/handlers/HandleSetter.java | 14 ++++++- .../lombok/javac/handlers/JavacHandlerUtil.java | 30 ++++++++++++- 11 files changed, 128 insertions(+), 20 deletions(-) (limited to 'src/core/lombok') diff --git a/src/core/lombok/javac/HandlerLibrary.java b/src/core/lombok/javac/HandlerLibrary.java index 30aeff73..3c61696b 100644 --- a/src/core/lombok/javac/HandlerLibrary.java +++ b/src/core/lombok/javac/HandlerLibrary.java @@ -44,6 +44,7 @@ import lombok.core.TypeResolver; import lombok.core.configuration.ConfigurationKeysLoader; import lombok.javac.handlers.JavacHandlerUtil; +import com.sun.source.util.Trees; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -148,12 +149,12 @@ public class HandlerLibrary { * then uses SPI discovery to load all annotation and visitor based handlers so that future calls * to the handle methods will defer to these handlers. */ - public static HandlerLibrary load(Messager messager) { + public static HandlerLibrary load(Messager messager, Trees trees) { HandlerLibrary library = new HandlerLibrary(messager); try { - loadAnnotationHandlers(library); - loadVisitorHandlers(library); + loadAnnotationHandlers(library, trees); + loadVisitorHandlers(library, trees); } catch (IOException e) { System.err.println("Lombok isn't running due to misconfigured SPI files: " + e); } @@ -165,9 +166,10 @@ public class HandlerLibrary { /** Uses SPI Discovery to find implementations of {@link JavacAnnotationHandler}. */ @SuppressWarnings({"rawtypes", "unchecked"}) - private static void loadAnnotationHandlers(HandlerLibrary lib) throws IOException { + private static void loadAnnotationHandlers(HandlerLibrary lib, Trees trees) throws IOException { //No, that seemingly superfluous reference to JavacAnnotationHandler's classloader is not in fact superfluous! for (JavacAnnotationHandler handler : SpiLoadUtil.findServices(JavacAnnotationHandler.class, JavacAnnotationHandler.class.getClassLoader())) { + handler.setTrees(trees); Class annotationClass = handler.getAnnotationHandledByThisHandler(); AnnotationHandlerContainer container = new AnnotationHandlerContainer(handler, annotationClass); String annotationClassName = container.annotationClass.getName().replace("$", "."); @@ -179,9 +181,10 @@ public class HandlerLibrary { } /** Uses SPI Discovery to find implementations of {@link JavacASTVisitor}. */ - private static void loadVisitorHandlers(HandlerLibrary lib) throws IOException { + private static void loadVisitorHandlers(HandlerLibrary lib, Trees trees) throws IOException { //No, that seemingly superfluous reference to JavacASTVisitor's classloader is not in fact superfluous! for (JavacASTVisitor visitor : SpiLoadUtil.findServices(JavacASTVisitor.class, JavacASTVisitor.class.getClassLoader())) { + visitor.setTrees(trees); lib.visitorHandlers.add(new VisitorContainer(visitor)); } } diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 106a29ae..ca409ad9 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 The Project Lombok Authors. + * Copyright (C) 2009-2017 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/core/lombok/javac/JavacASTAdapter.java b/src/core/lombok/javac/JavacASTAdapter.java index 5d120a77..6af53e3d 100644 --- a/src/core/lombok/javac/JavacASTAdapter.java +++ b/src/core/lombok/javac/JavacASTAdapter.java @@ -21,6 +21,7 @@ */ package lombok.javac; +import com.sun.source.util.Trees; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -34,6 +35,9 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; * has been implemented with an empty body. Override whichever methods you need. */ public class JavacASTAdapter implements JavacASTVisitor { + /** {@inheritDoc} */ + @Override public void setTrees(Trees trees) {} + /** {@inheritDoc} */ @Override public void visitCompilationUnit(JavacNode top, JCCompilationUnit unit) {} diff --git a/src/core/lombok/javac/JavacASTVisitor.java b/src/core/lombok/javac/JavacASTVisitor.java index c57e657a..565980f9 100644 --- a/src/core/lombok/javac/JavacASTVisitor.java +++ b/src/core/lombok/javac/JavacASTVisitor.java @@ -23,6 +23,7 @@ package lombok.javac; import java.io.PrintStream; +import com.sun.source.util.Trees; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -37,6 +38,8 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; * calling the appropriate visit and endVisit methods. */ public interface JavacASTVisitor { + void setTrees(Trees trees); + /** * Called at the very beginning and end. */ @@ -121,6 +124,8 @@ public interface JavacASTVisitor { this.out = out; } + @Override public void setTrees(Trees trees) {} + private void forcePrint(String text, Object... params) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < indent; i++) sb.append(" "); diff --git a/src/core/lombok/javac/JavacAnnotationHandler.java b/src/core/lombok/javac/JavacAnnotationHandler.java index a86aa6c6..dd4e7098 100644 --- a/src/core/lombok/javac/JavacAnnotationHandler.java +++ b/src/core/lombok/javac/JavacAnnotationHandler.java @@ -26,6 +26,7 @@ import java.lang.annotation.Annotation; import lombok.core.AnnotationValues; import lombok.core.SpiLoadUtil; +import com.sun.source.util.Trees; import com.sun.tools.javac.tree.JCTree.JCAnnotation; /** @@ -40,6 +41,8 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation; * You also need to register yourself via SPI discovery as being an implementation of {@code JavacAnnotationHandler}. */ public abstract class JavacAnnotationHandler { + protected Trees trees; + /** * Called when an annotation is found that is likely to match the annotation you're interested in. * @@ -63,4 +66,8 @@ public abstract class JavacAnnotationHandler { @SuppressWarnings("unchecked") public Class getAnnotationHandledByThisHandler() { return (Class) SpiLoadUtil.findAnnotationClass(getClass(), JavacAnnotationHandler.class); } + + public void setTrees(Trees trees) { + this.trees = trees; + } } diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index 727692ac..fa24c2f9 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2013 The Project Lombok Authors. + * Copyright (C) 2009-2017 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ package lombok.javac; import java.util.List; +import javax.lang.model.element.Element; import javax.tools.Diagnostic; import lombok.core.AST.Kind; @@ -51,6 +52,13 @@ public class JavacNode extends lombok.core.LombokNode getPriorities() { @@ -54,7 +55,7 @@ public class JavacTransformer { public void transform(long priority, Context context, java.util.List compilationUnitsRaw) { List compilationUnits; if (compilationUnitsRaw instanceof List) { - compilationUnits = (List)compilationUnitsRaw; + compilationUnits = (List) compilationUnitsRaw; } else { compilationUnits = List.nil(); for (int i = compilationUnitsRaw.size() -1; i >= 0; i--) { diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 6547c143..6e229279 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Project Lombok Authors. + * Copyright (C) 2009-2017 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -67,7 +67,6 @@ import com.sun.tools.javac.util.Context; */ @SupportedAnnotationTypes("*") public class LombokProcessor extends AbstractProcessor { - private JavacProcessingEnvironment processingEnv; private JavacTransformer transformer; private Trees trees; @@ -82,9 +81,14 @@ public class LombokProcessor extends AbstractProcessor { } this.processingEnv = (JavacProcessingEnvironment) procEnv; + String beforeOurs = listAnnotationProcessorsBeforeOurs(); + if (beforeOurs != null) { + procEnv.getMessager().printMessage(Kind.NOTE, "Lombok is not the first annotation processor in the lineup. Configure your build tool with an explicit list of processors so that lombok is first. See https://projectlombok.org/configureMultipleProcessors for more. Processors before lombok in the lineup: " + beforeOurs); + } + placePostCompileAndDontMakeForceRoundDummiesHook(); - transformer = new JavacTransformer(procEnv.getMessager()); trees = Trees.instance(procEnv); + transformer = new JavacTransformer(procEnv.getMessager(), trees); SortedSet p = transformer.getPriorities(); if (p.isEmpty()) { this.priorityLevels = new long[] {0L}; @@ -97,6 +101,45 @@ public class LombokProcessor extends AbstractProcessor { } } + private static final String JPE = "com.sun.tools.javac.processing.JavacProcessingEnvironment"; + private static final Field javacProcessingEnvironment_discoveredProcs = getFieldAccessor(JPE, "discoveredProcs"); + private static final Field discoveredProcessors_procStateList = getFieldAccessor(JPE + "$DiscoveredProcessors", "procStateList"); + private static final Field processorState_processor = getFieldAccessor(JPE + "$processor", "processor"); + + private static final Field getFieldAccessor(String typeName, String fieldName) { + try { + Class c = Class.forName(typeName); + Field f = c.getDeclaredField(fieldName); + f.setAccessible(true); + return f; + } catch (ClassNotFoundException e) { + return null; + } catch (NoSuchFieldException e) { + return null; + } + } + + private String listAnnotationProcessorsBeforeOurs() { + try { + Object discoveredProcessors = javacProcessingEnvironment_discoveredProcs.get(this.processingEnv); + ArrayList states = (ArrayList) discoveredProcessors_procStateList.get(discoveredProcessors); + if (states == null || states.isEmpty()) return null; + if (states.size() == 1) return processorState_processor.get(states.get(0)).getClass().getName(); + + int idx = 0; + StringBuilder out = new StringBuilder(); + for (Object processState : states) { + idx++; + String name = processorState_processor.get(processState).getClass().getName(); + if (out.length() > 0) out.append(", "); + out.append("[").append(idx).append("] ").append(name); + } + return out.toString(); + } catch (Exception e) { + return null; + } + } + private void placePostCompileAndDontMakeForceRoundDummiesHook() { stopJavacProcessingEnvironmentFromClosingOurClassloader(); diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 0a2fe362..60dbe8ee 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 The Project Lombok Authors. + * Copyright (C) 2009-2017 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -46,6 +46,7 @@ import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; 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.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCBinary; @@ -219,7 +220,7 @@ public class HandleGetter extends JavacAnnotationHandler { long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC); - injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source.get(), lazy, onMethod)); + injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source.get(), lazy, onMethod), List.nil(), getMirrorForFieldType(fieldNode)); } public JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker treeMaker, JCTree source, boolean lazy, List onMethod) { diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 3c4329b2..9c5061f5 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2017 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -188,7 +188,17 @@ public class HandleSetter extends JavacAnnotationHandler { long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC); JCMethodDecl createdSetter = createSetter(access, fieldNode, fieldNode.getTreeMaker(), sourceNode, onMethod, onParam); - injectMethod(fieldNode.up(), createdSetter); + Type fieldType = getMirrorForFieldType(fieldNode); + Type returnType; + + if (shouldReturnThis(fieldNode)) { + ClassSymbol sym = ((JCClassDecl) fieldNode.up().get()).sym; + returnType = sym == null ? null : sym.type; + } else { + returnType = Javac.createVoidType(fieldNode.getSymbolTable(), CTC_VOID); + } + + injectMethod(fieldNode.up(), createdSetter, fieldType == null ? null : List.of(fieldType), returnType); } public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, JavacNode source, List onMethod, List onParam) { diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index efa67604..a33f9b17 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Project Lombok Authors. + * Copyright (C) 2009-2017 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,6 +37,8 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.lang.model.element.Element; + import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.Data; @@ -59,7 +61,12 @@ import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Scope; import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Type.MethodType; import com.sun.tools.javac.parser.Tokens.Comment; import com.sun.tools.javac.tree.DocCommentTable; import com.sun.tools.javac.tree.JCTree; @@ -819,6 +826,12 @@ public class JavacHandlerUtil { return call; } + public static Type getMirrorForFieldType(JavacNode fieldNode) { + Element fieldElement = fieldNode.getElement(); + if (fieldElement instanceof VarSymbol) return ((VarSymbol) fieldElement).type; + return null; + } + /** * Adds the given new field declaration to the provided type AST Node. * The field carries the @{@link SuppressWarnings}("all") annotation. @@ -903,13 +916,17 @@ public class JavacHandlerUtil { } } + public static void injectMethod(JavacNode typeNode, JCMethodDecl method) { + injectMethod(typeNode, method, null, null); + } + /** * Adds the given new method declaration to the provided type AST Node. * Can also inject constructors. * * Also takes care of updating the JavacAST. */ - public static void injectMethod(JavacNode typeNode, JCMethodDecl method) { + public static void injectMethod(JavacNode typeNode, JCMethodDecl method, List paramTypes, Type returnType) { JCClassDecl type = (JCClassDecl) typeNode.get(); if (method.getName().contentEquals("")) { @@ -933,9 +950,18 @@ public class JavacHandlerUtil { addGenerated(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext()); type.defs = type.defs.append(method); + fixMethodMirror(typeNode.getContext(), typeNode.getElement(), method.getModifiers().flags, method.getName(), paramTypes, returnType); + typeNode.add(method, Kind.METHOD); } + private static void fixMethodMirror(Context context, Element typeMirror, long access, Name methodName, List paramTypes, Type returnType) { + if (typeMirror == null || paramTypes == null || returnType == null) return; + ClassSymbol cs = (ClassSymbol) typeMirror; + MethodSymbol methodSymbol = new MethodSymbol(access, methodName, new MethodType(paramTypes, returnType, List.nil(), Symtab.instance(context).methodClass), cs); + cs.members_field.enter(methodSymbol); + } + /** * Adds an inner type (class, interface, enum) to the given type. Cannot inject top-level types. * -- cgit