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.

This commit is contained in:
Reinier Zwitserloot committed 2017-01-19 21:53:00 +01:00
1 parent cc28ef24ec
commit b867f81b8a
15 files changed
+154 -27

No files matched your search

+2 -2
View File
@@ -797,7 +797,7 @@ You can also create your own by writing a 'testenvironment.properties' file. The
<delete dir="build/useTestAp" quiet="true" />
<mkdir dir="build/useTestAp" />
<javac source="1.7" target="1.7" destdir="build/useTestAp" includeantruntime="false">
<javac verbose="false" source="1.7" target="1.7" destdir="build/useTestAp" includeantruntime="false">
<src path="src/useTestAP" />
<classpath location="dist/lombok.jar" />
<classpath location="dist/testAp.jar" />
@@ -809,7 +809,7 @@ You can also create your own by writing a 'testenvironment.properties' file. The
<delete dir="build/useTestAp" quiet="true" />
<mkdir dir="build/useTestAp" />
<javac source="1.7" target="1.7" destdir="build/useTestAp" includeantruntime="false">
<javac verbose="false" source="1.7" target="1.7" destdir="build/useTestAp" includeantruntime="false">
<src path="src/useTestAP" />
<classpath location="dist/lombok.jar" />
<classpath location="dist/testAp.jar" />
+8 -5
View File
@@ -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<? extends Annotation> 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));
}
}
+1 -1
View File
@@ -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
@@ -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) {}
@@ -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(" ");
@@ -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<T extends Annotation> {
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<T extends Annotation> {
@SuppressWarnings("unchecked") public Class<T> getAnnotationHandledByThisHandler() {
return (Class<T>) SpiLoadUtil.findAnnotationClass(getClass(), JavacAnnotationHandler.class);
}
public void setTrees(Trees trees) {
this.trees = trees;
}
}
+9 -1
View File
@@ -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<JavacAST, JavacNode, JCTre
super(ast, node, children, kind);
}
public Element getElement() {
if (node instanceof JCClassDecl) return ((JCClassDecl) node).sym;
if (node instanceof JCMethodDecl) return ((JCMethodDecl) node).sym;
if (node instanceof JCVariableDecl) return ((JCVariableDecl) node).sym;
return null;
}
public int getEndPosition(DiagnosticPosition pos) {
JCCompilationUnit cu = (JCCompilationUnit) top().get();
return Javac.getEndPosition(pos, cu);
+5 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2012 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
@@ -26,6 +26,7 @@ import java.util.SortedSet;
import javax.annotation.processing.Messager;
import com.sun.source.util.Trees;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
@@ -38,9 +39,9 @@ public class JavacTransformer {
private final HandlerLibrary handlers;
private final Messager messager;
public JavacTransformer(Messager messager) {
public JavacTransformer(Messager messager, Trees trees) {
this.messager = messager;
this.handlers = HandlerLibrary.load(messager);
this.handlers = HandlerLibrary.load(messager, trees);
}
public SortedSet<Long> getPriorities() {
@@ -54,7 +55,7 @@ public class JavacTransformer {
public void transform(long priority, Context context, java.util.List<JCCompilationUnit> compilationUnitsRaw) {
List<JCCompilationUnit> compilationUnits;
if (compilationUnitsRaw instanceof List<?>) {
compilationUnits = (List<JCCompilationUnit>)compilationUnitsRaw;
compilationUnits = (List<JCCompilationUnit>) compilationUnitsRaw;
} else {
compilationUnits = List.nil();
for (int i = compilationUnitsRaw.size() -1; i >= 0; i--) {
+46 -3
View File
@@ -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<Long> 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();
@@ -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<Getter> {
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.<Type>nil(), getMirrorForFieldType(fieldNode));
}
public JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker treeMaker, JCTree source, boolean lazy, List<JCAnnotation> onMethod) {
@@ -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<Setter> {
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<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
@@ -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 &#64;{@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<Type> paramTypes, Type returnType) {
JCClassDecl type = (JCClassDecl) typeNode.get();
if (method.getName().contentEquals("<init>")) {
@@ -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<Type> 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.<Type>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.
*
@@ -36,6 +36,11 @@ import javax.lang.model.element.TypeElement;
class AnnotationProcessorHider {
public static class AnnotationProcessor extends AbstractProcessor {
private static final long START = System.currentTimeMillis();
private void log(String txt) {
System.out.printf("***[%3d]: %s\n", System.currentTimeMillis() - START, txt);
}
private final AbstractProcessor instance = createWrappedInstance();
@Override public Set<String> getSupportedOptions() {
@@ -51,11 +56,15 @@ class AnnotationProcessorHider {
}
@Override public void init(ProcessingEnvironment processingEnv) {
log("Lombok in init");
instance.init(processingEnv);
super.init(processingEnv);
}
private int roundCounter = 0;
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
roundCounter++;
log("Lombok in round " + roundCounter);
return instance.process(annotations, roundEnv);
}
@@ -30,7 +30,9 @@ import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
@SupportedAnnotationTypes("org.projectlombok.testAp.ExampleAnnotation")
public final class TestAp extends AbstractProcessor {
@@ -54,14 +56,17 @@ public final class TestAp extends AbstractProcessor {
for (Element annotated : roundEnv.getElementsAnnotatedWith(ExampleAnnotation.class)) {
annotatedElemCount++;
for (Element child : annotated.getEnclosedElements()) {
if (child.getSimpleName().equals("getTest") && child.getKind() == ElementKind.METHOD) foundGetTest = true;
System.out.println(child);
if (child.getSimpleName().toString().equals("getTest") && child.getKind() == ElementKind.METHOD) foundGetTest = true;
if (child instanceof ExecutableElement) {
TypeMirror returnType = ((ExecutableElement) child).getReturnType();
System.out.println("RETURN TYPE for " + child.getSimpleName() + ": " + returnType.getClass() + " -- " + returnType.toString());
}
}
}
if (foundGetTest) log("RESULT: POSITIVE -- found the getTest method");
else if (annotatedElemCount > 0) log("RESULT: NEGATIVE-T1 -- found the example class but there's no getTest method in it according to the type mirror.");
else log("RESULT: NEGATIVE-T2 -- The example class is not provided by 'getElementsAnnotatedWith' in this rond.");
else if (annotatedElemCount > 0) log("RESULT: NEGATIVE -- found the example class but there's no getTest method in it according to the type mirror.");
else log("RESULT: AMBIVALENT -- The example class is not provided by 'getElementsAnnotatedWith' in this round. Not an issue, unless previously you got a NEGATIVE result.");
return false;
}
+6 -1
View File
@@ -1,8 +1,13 @@
@org.projectlombok.testAp.ExampleAnnotation
//@lombok.experimental.Accessors(chain=true)
public class UseTestAp {
@lombok.Getter String test;
@lombok.Setter @lombok.Getter String test;
public void confirmGetTestExists() {
System.out.println(getTest());
}
public UseTestAp returningSelf() {
return this;
}
}