diff options
author | Roel Spilker <r.spilker@gmail.com> | 2013-11-19 21:02:59 +0100 |
---|---|---|
committer | Roel Spilker <r.spilker@gmail.com> | 2013-11-19 21:02:59 +0100 |
commit | 78b2d6919e35887940f9f11b6ae1731245739b83 (patch) | |
tree | 0dc305883c19a862a38669374c5614e26480d4b8 /src | |
parent | 5deb185591904d275cb06eea85c0d739587fc738 (diff) | |
parent | 83b7e77b0cce6cd5993b17f36164271accdd281c (diff) | |
download | lombok-78b2d6919e35887940f9f11b6ae1731245739b83.tar.gz lombok-78b2d6919e35887940f9f11b6ae1731245739b83.tar.bz2 lombok-78b2d6919e35887940f9f11b6ae1731245739b83.zip |
Merge branch 'master' of github.com:rzwitserloot/lombok
Conflicts:
src/delombok/lombok/delombok/DelombokApp.java
Diffstat (limited to 'src')
67 files changed, 2992 insertions, 1411 deletions
diff --git a/src/core/lombok/core/TransformationsUtil.java b/src/core/lombok/core/TransformationsUtil.java index 8959ad7a..8c7fbd3f 100644 --- a/src/core/lombok/core/TransformationsUtil.java +++ b/src/core/lombok/core/TransformationsUtil.java @@ -70,9 +70,11 @@ public class TransformationsUtil { * @param prefixes A list of prefixes, usually provided by the {@code Accessors} settings annotation, listing field prefixes. * @return The base name of the field. */ - private static CharSequence removePrefix(CharSequence fieldName, String[] prefixes) { + public static CharSequence removePrefix(CharSequence fieldName, String[] prefixes) { if (prefixes == null || prefixes.length == 0) return fieldName; + fieldName = fieldName.toString(); + outer: for (String prefix : prefixes) { if (prefix.length() == 0) return fieldName; @@ -176,6 +178,7 @@ public class TransformationsUtil { private static String toAccessorName(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean, String booleanPrefix, String normalPrefix, boolean adhereToFluent) { + fieldName = fieldName.toString(); if (fieldName.length() == 0) return null; Accessors ac = accessors == null ? null : accessors.getInstance(); diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index bd83c1f8..bf2e199b 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-2013 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 @@ -28,8 +28,9 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "0.12.1"; - private static final String RELEASE_NAME = "Angry Butterfy"; + private static final String VERSION = "1.12.3"; + private static final String RELEASE_NAME = "Edgy Guinea Pig"; +// private static final String RELEASE_NAME = "Angry Butterfly"; private Version() { //Prevent instantiation diff --git a/src/core/lombok/core/debug/DebugSnapshotStore.java b/src/core/lombok/core/debug/DebugSnapshotStore.java index 64c91473..11192bd3 100644 --- a/src/core/lombok/core/debug/DebugSnapshotStore.java +++ b/src/core/lombok/core/debug/DebugSnapshotStore.java @@ -82,7 +82,7 @@ public class DebugSnapshotStore { } try { - File logFile = new File(System.getProperty("user.home", "."), String.format("lombok164-%d.err", System.currentTimeMillis())); + File logFile = new File(System.getProperty("user.home", "."), String.format("lombokdss-%d.err", System.currentTimeMillis())); OutputStream stream = new FileOutputStream(logFile); try { stream.write(out.toString().getBytes("UTF-8")); diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 9bd634f7..5e322c90 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1125,6 +1125,37 @@ public class EclipseHandlerUtil { return true; } + public static char[] removePrefixFromField(EclipseNode field) { + String[] prefixes = null; + for (EclipseNode node : field.down()) { + if (annotationTypeMatches(Accessors.class, node)) { + prefixes = createAnnotation(Accessors.class, node).getInstance().prefix(); + break; + } + } + + if (prefixes == null) { + EclipseNode current = field.up(); + outer: + while (current != null) { + for (EclipseNode node : current.down()) { + if (annotationTypeMatches(Accessors.class, node)) { + prefixes = createAnnotation(Accessors.class, node).getInstance().prefix(); + break outer; + } + } + current = current.up(); + } + } + + if (prefixes != null && prefixes.length > 0) { + CharSequence newName = TransformationsUtil.removePrefix(field.getName(), prefixes); + if (newName != null) return newName.toString().toCharArray(); + } + + return ((FieldDeclaration) field.get()).name; + } + public static AnnotationValues<Accessors> getAccessorsForField(EclipseNode field) { for (EclipseNode node : field.down()) { if (annotationTypeMatches(Accessors.class, node)) { @@ -1562,9 +1593,9 @@ public class EclipseHandlerUtil { intLiteralFactoryMethod = intLiteralFactoryMethod_; } - private static boolean isAllUnderscores(char[] in) { + private static boolean isAllValidOnXCharacters(char[] in) { if (in == null || in.length == 0) return false; - for (char c : in) if (c != '_') return false; + for (char c : in) if (c != '_' && c != 'X' && c != 'x' && c != '$') return false; return true; } @@ -1597,31 +1628,31 @@ public class EclipseHandlerUtil { if (i > 0) System.arraycopy(pairs, 0, newPairs, 0, i); if (i < pairs.length - 1) System.arraycopy(pairs, i + 1, newPairs, i, pairs.length - i - 1); normalAnnotation.memberValuePairs = newPairs; - // We have now removed the annotation parameter and stored '@_({... annotations ...})', + // We have now removed the annotation parameter and stored '@__({... annotations ...})', // which we must now unbox. if (!(value instanceof Annotation)) { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); return Collections.emptyList(); } - Annotation atUnderscore = (Annotation) value; - if (!(atUnderscore.type instanceof SingleTypeReference) || - !isAllUnderscores(((SingleTypeReference) atUnderscore.type).token)) { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + Annotation atDummyIdentifier = (Annotation) value; + if (!(atDummyIdentifier.type instanceof SingleTypeReference) || + !isAllValidOnXCharacters(((SingleTypeReference) atDummyIdentifier.type).token)) { + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); return Collections.emptyList(); } - if (atUnderscore instanceof MarkerAnnotation) { - // It's @getter(onMethod=@_). This is weird, but fine. + if (atDummyIdentifier instanceof MarkerAnnotation) { + // It's @Getter(onMethod=@__). This is weird, but fine. return Collections.emptyList(); } Expression content = null; - if (atUnderscore instanceof NormalAnnotation) { - MemberValuePair[] mvps = ((NormalAnnotation) atUnderscore).memberValuePairs; + if (atDummyIdentifier instanceof NormalAnnotation) { + MemberValuePair[] mvps = ((NormalAnnotation) atDummyIdentifier).memberValuePairs; if (mvps == null || mvps.length == 0) { - // It's @getter(onMethod=@_()). This is weird, but fine. + // It's @Getter(onMethod=@__()). This is weird, but fine. return Collections.emptyList(); } if (mvps.length == 1 && Arrays.equals("value".toCharArray(), mvps[0].name)) { @@ -1629,12 +1660,12 @@ public class EclipseHandlerUtil { } } - if (atUnderscore instanceof SingleMemberAnnotation) { - content = ((SingleMemberAnnotation) atUnderscore).memberValue; + if (atDummyIdentifier instanceof SingleMemberAnnotation) { + content = ((SingleMemberAnnotation) atDummyIdentifier).memberValue; } if (content == null) { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); return Collections.emptyList(); } @@ -1646,13 +1677,13 @@ public class EclipseHandlerUtil { if (expressions != null) for (Expression ex : expressions) { if (ex instanceof Annotation) result.add((Annotation) ex); else { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); return Collections.emptyList(); } } return result; } else { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); return Collections.emptyList(); } } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 70110a9c..981d77dc 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -113,7 +113,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { // non-final fields final, but @Value's handler hasn't done this yet, so we have to do this math ourselves. // Value will only skip making a field final if it has an explicit @NonFinal annotation, so we check for that. if (fd.initialization != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue; - namesOfParameters.add(fd.name); + namesOfParameters.add(removePrefixFromField(fieldNode)); typesOfParameters.add(fd.type); fields.add(fieldNode); } diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 1ae680d9..22285b2d 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -230,7 +230,8 @@ public class HandleConstructor { int ctr = 0; for (EclipseNode field : fields) { - fieldNames.expressions[ctr] = new StringLiteral(field.getName().toCharArray(), pS, pE, 0); + char[] fieldName = removePrefixFromField(field); + fieldNames.expressions[ctr] = new StringLiteral(fieldName, pS, pE, 0); setGeneratedBy(fieldNames.expressions[ctr], source); ctr++; } @@ -273,15 +274,17 @@ public class HandleConstructor { for (EclipseNode fieldNode : fields) { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); - FieldReference thisX = new FieldReference(field.name, p); + char[] rawName = field.name; + char[] fieldName = removePrefixFromField(fieldNode); + FieldReference thisX = new FieldReference(rawName, p); thisX.receiver = new ThisReference((int)(p >> 32), (int)p); - SingleNameReference assignmentNameRef = new SingleNameReference(field.name, p); + SingleNameReference assignmentNameRef = new SingleNameReference(fieldName, p); Assignment assignment = new Assignment(thisX, assignmentNameRef, (int)p); assignment.sourceStart = (int)(p >> 32); assignment.sourceEnd = assignment.statementEnd = (int)(p >> 32); assigns.add(assignment); long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; - Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); + Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL); Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN); Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN); if (nonNulls.length != 0) { diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 6990e609..3c8a7039 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -221,7 +221,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH // The user code couldn't possibly (barring really weird subclassing shenanigans) be in a shippable state anyway; the implementations of these 3 methods are // all inter-related and should be written by the same entity. String msg = String.format("Not generating %s: One of equals, hashCode, and canEqual exists. " + - "You should either write all of these are none of these (in the latter case, lombok generates them).", + "You should either write all of these or none of these (in the latter case, lombok generates them).", equalsExists == MemberExistsResult.NOT_EXISTS && hashCodeExists == MemberExistsResult.NOT_EXISTS ? "equals and hashCode" : equalsExists == MemberExistsResult.NOT_EXISTS ? "equals" : "hashCode"); errorNode.addWarning(msg); diff --git a/src/core/lombok/eclipse/handlers/NonNullHandler.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java index 5c58069c..634cb2d9 100644 --- a/src/core/lombok/eclipse/handlers/NonNullHandler.java +++ b/src/core/lombok/eclipse/handlers/HandleNonNull.java @@ -21,8 +21,19 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.Eclipse.isPrimitive; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + import java.util.Arrays; +import lombok.NonNull; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.eclipse.DeferUntilPostDiet; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; + import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; @@ -36,22 +47,15 @@ import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; +import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.mangosdk.spi.ProviderFor; -import lombok.NonNull; -import lombok.core.AST.Kind; -import lombok.core.AnnotationValues; -import lombok.eclipse.DeferUntilPostDiet; -import lombok.eclipse.EclipseAnnotationHandler; -import lombok.eclipse.EclipseNode; - -import static lombok.eclipse.Eclipse.*; -import static lombok.eclipse.handlers.EclipseHandlerUtil.*; - @DeferUntilPostDiet @ProviderFor(EclipseAnnotationHandler.class) -public class NonNullHandler extends EclipseAnnotationHandler<NonNull> { +@HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first. +public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { @Override public void handle(AnnotationValues<NonNull> annotation, Annotation ast, EclipseNode annotationNode) { if (annotationNode.up().getKind() == Kind.FIELD) { // This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc), @@ -82,6 +86,11 @@ public class NonNullHandler extends EclipseAnnotationHandler<NonNull> { if (isGenerated(declaration)) return; + if (declaration.isAbstract()) { + annotationNode.addWarning("@NonNull is meaningless on a parameter of an abstract method."); + return; + } + // Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter, // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and // wrap all references to it in the super/this to a call to this method. @@ -98,16 +107,31 @@ public class NonNullHandler extends EclipseAnnotationHandler<NonNull> { declaration.statements = new Statement[] {nullCheck}; } else { char[] expectedName = arg.name; - for (Statement stat : declaration.statements) { - char[] varNameOfNullCheck = returnVarNameIfNullCheck(stat); - if (varNameOfNullCheck == null) break; - if (Arrays.equals(expectedName, varNameOfNullCheck)) return; + /* Abort if the null check is already there, delving into try and synchronized statements */ { + Statement[] stats = declaration.statements; + int idx = 0; + while (stats != null && stats.length > idx) { + Statement stat = stats[idx++]; + if (stat instanceof TryStatement) { + stats = ((TryStatement) stat).tryBlock.statements; + idx = 0; + continue; + } + if (stat instanceof SynchronizedStatement) { + stats = ((SynchronizedStatement) stat).block.statements; + idx = 0; + continue; + } + char[] varNameOfNullCheck = returnVarNameIfNullCheck(stat); + if (varNameOfNullCheck == null) break; + if (Arrays.equals(varNameOfNullCheck, expectedName)) return; + } } Statement[] newStatements = new Statement[declaration.statements.length + 1]; int skipOver = 0; for (Statement stat : declaration.statements) { - if (isGenerated(stat)) skipOver++; + if (isGenerated(stat) && isNullCheck(stat)) skipOver++; else break; } System.arraycopy(declaration.statements, 0, newStatements, 0, skipOver); @@ -118,6 +142,10 @@ public class NonNullHandler extends EclipseAnnotationHandler<NonNull> { annotationNode.up().up().rebuild(); } + private boolean isNullCheck(Statement stat) { + return returnVarNameIfNullCheck(stat) != null; + } + private char[] returnVarNameIfNullCheck(Statement stat) { if (!(stat instanceof IfStatement)) return null; diff --git a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java index aa78ca3b..d3a95db8 100644 --- a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java @@ -30,6 +30,7 @@ import java.util.List; import lombok.SneakyThrows; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; @@ -60,6 +61,7 @@ import org.mangosdk.spi.ProviderFor; */ @ProviderFor(EclipseAnnotationHandler.class) @DeferUntilPostDiet +@HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSneakyThrows extends EclipseAnnotationHandler<SneakyThrows> { private static class DeclaredException { diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index e4c58eab..f76f06ed 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -27,6 +27,7 @@ import java.lang.reflect.Modifier; import lombok.Synchronized; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.core.AST.Kind; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; @@ -52,6 +53,7 @@ import org.mangosdk.spi.ProviderFor; */ @ProviderFor(EclipseAnnotationHandler.class) @DeferUntilPostDiet +@HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSynchronized extends EclipseAnnotationHandler<Synchronized> { private static final char[] INSTANCE_LOCK_NAME = "$lock".toCharArray(); private static final char[] STATIC_LOCK_NAME = "$LOCK".toCharArray(); diff --git a/src/core/lombok/javac/CapturingDiagnosticListener.java b/src/core/lombok/javac/CapturingDiagnosticListener.java index 45b4047a..a0ac6adc 100644 --- a/src/core/lombok/javac/CapturingDiagnosticListener.java +++ b/src/core/lombok/javac/CapturingDiagnosticListener.java @@ -52,7 +52,7 @@ public class CapturingDiagnosticListener implements DiagnosticListener<JavaFileO "^" + Pattern.quote(file.getAbsolutePath()) + "\\s*:\\s*\\d+\\s*:\\s*(?:warning:\\s*)?(.*)$", Pattern.DOTALL).matcher(msg); if (m.matches()) msg = m.group(1); - messages.add(new CompilerMessage(d.getLineNumber(), d.getColumnNumber(), d.getStartPosition(), d.getKind() == Kind.ERROR, msg)); + messages.add(new CompilerMessage(d.getLineNumber(), d.getStartPosition(), d.getKind() == Kind.ERROR, msg)); } public void suppress(int start, int end) { @@ -67,15 +67,12 @@ public class CapturingDiagnosticListener implements DiagnosticListener<JavaFileO /** Line Number (starting at 1) */ private final long line; - /** Preferably column, but if that is hard to calculate (e.g. in ecj), then position is acceptable. */ - private final long columnOrPosition; private final long position; private final boolean isError; private final String message; - public CompilerMessage(long line, long columnOrPosition, long position, boolean isError, String message) { + public CompilerMessage(long line, long position, boolean isError, String message) { this.line = line; - this.columnOrPosition = columnOrPosition; this.position = position; this.isError = isError; this.message = message; @@ -89,10 +86,6 @@ public class CapturingDiagnosticListener implements DiagnosticListener<JavaFileO return position; } - public long getColumnOrPosition() { - return columnOrPosition; - } - public boolean isError() { return isError; } @@ -107,7 +100,6 @@ public class CapturingDiagnosticListener implements DiagnosticListener<JavaFileO result = prime * result + (isError ? 1231 : 1237); result = prime * result + (int) (line ^ (line >>> 32)); result = prime * result + ((message == null) ? 0 : message.hashCode()); - result = prime * result + (int) (columnOrPosition ^ (columnOrPosition >>> 32)); return result; } @@ -121,12 +113,11 @@ public class CapturingDiagnosticListener implements DiagnosticListener<JavaFileO if (message == null) { if (other.message != null) return false; } else if (!message.equals(other.message)) return false; - if (columnOrPosition != other.columnOrPosition) return false; return true; } @Override public String toString() { - return String.format("%d:%d %s %s", line, columnOrPosition, isError ? "ERROR" : "WARNING", message); + return String.format("%d %s %s", line, isError ? "ERROR" : "WARNING", message); } } } diff --git a/src/core/lombok/javac/CompilerMessageSuppressor.java b/src/core/lombok/javac/CompilerMessageSuppressor.java new file mode 100644 index 00000000..a17e0c62 --- /dev/null +++ b/src/core/lombok/javac/CompilerMessageSuppressor.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2011-2013 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 + * 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; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; + +/** + * During resolution, the resolver will emit resolution errors, but without appropriate file names and line numbers. If these resolution errors stick around + * then they will be generated AGAIN, this time with proper names and line numbers, at the end. Therefore, we want to suppress the logger. + */ +public final class CompilerMessageSuppressor { + private final Log log; + private static final Field errWriterField, warnWriterField, noticeWriterField, dumpOnErrorField, promptOnErrorField, diagnosticListenerField; + private static final Field deferDiagnosticsField, deferredDiagnosticsField, diagnosticHandlerField; + private static final ConcurrentMap<Class<?>, Field> handlerDeferredFields = new ConcurrentHashMap<Class<?>, Field>(); + private static final Field NULL_FIELD; + private PrintWriter errWriter, warnWriter, noticeWriter; + private Boolean dumpOnError, promptOnError; + private DiagnosticListener<?> contextDiagnosticListener, logDiagnosticListener; + private final Context context; + + // If this is true, the fields changed. Better to print weird error messages than to fail outright. + private static final boolean dontBother; + + private static final ThreadLocal<Queue<?>> queueCache = new ThreadLocal<Queue<?>>(); + + static { + errWriterField = getDeclaredField(Log.class, "errWriter"); + warnWriterField = getDeclaredField(Log.class, "warnWriter"); + noticeWriterField = getDeclaredField(Log.class, "noticeWriter"); + dumpOnErrorField = getDeclaredField(Log.class, "dumpOnError"); + promptOnErrorField = getDeclaredField(Log.class, "promptOnError"); + diagnosticListenerField = getDeclaredField(Log.class, "diagListener"); + + dontBother = + errWriterField == null || + warnWriterField == null || + noticeWriterField == null || + dumpOnErrorField == null || + promptOnErrorField == null || + diagnosticListenerField == null; + + + deferDiagnosticsField = getDeclaredField(Log.class, "deferDiagnostics"); + deferredDiagnosticsField = getDeclaredField(Log.class, "deferredDiagnostics"); + + // javac8 + diagnosticHandlerField = getDeclaredField(Log.class, "diagnosticHandler"); + + NULL_FIELD = getDeclaredField(JavacResolution.class, "NULL_FIELD"); + } + + static Field getDeclaredField(Class<?> c, String fieldName) { + try { + Field field = c.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } + catch (Throwable t) { + return null; + } + } + + public CompilerMessageSuppressor(Context context) { + this.log = Log.instance(context); + this.context = context; + } + + public boolean disableLoggers() { + contextDiagnosticListener = context.get(DiagnosticListener.class); + context.put(DiagnosticListener.class, (DiagnosticListener<?>) null); + if (dontBother) return false; + boolean dontBotherInstance = false; + + PrintWriter dummyWriter = new PrintWriter(new OutputStream() { + @Override public void write(int b) throws IOException { + // Do nothing on purpose + } + }); + + if (deferDiagnosticsField != null) try { + if (Boolean.TRUE.equals(deferDiagnosticsField.get(log))) { + queueCache.set((Queue<?>) deferredDiagnosticsField.get(log)); + Queue<?> empty = new LinkedList<Object>(); + deferredDiagnosticsField.set(log, empty); + } + } catch (Exception e) {} + + if (diagnosticHandlerField != null) try { + Object handler = diagnosticHandlerField.get(log); + Field field = getDeferredField(handler); + if (field != null) { + queueCache.set((Queue<?>) field.get(handler)); + Queue<?> empty = new LinkedList<Object>(); + field.set(handler, empty); + } + } catch (Exception e) {} + + if (!dontBotherInstance) try { + errWriter = (PrintWriter) errWriterField.get(log); + errWriterField.set(log, dummyWriter); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + warnWriter = (PrintWriter) warnWriterField.get(log); + warnWriterField.set(log, dummyWriter); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + noticeWriter = (PrintWriter) noticeWriterField.get(log); + noticeWriterField.set(log, dummyWriter); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + dumpOnError = (Boolean) dumpOnErrorField.get(log); + dumpOnErrorField.set(log, false); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + promptOnError = (Boolean) promptOnErrorField.get(log); + promptOnErrorField.set(log, false); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + logDiagnosticListener = (DiagnosticListener<?>) diagnosticListenerField.get(log); + diagnosticListenerField.set(log, null); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (dontBotherInstance) enableLoggers(); + return !dontBotherInstance; + } + + private static Field getDeferredField(Object handler) { + Class<? extends Object> key = handler.getClass(); + Field field = handlerDeferredFields.get(key); + if (field != null) { + return field == NULL_FIELD ? null : field; + } + Field value = getDeclaredField(key, "deferred"); + handlerDeferredFields.put(key, value == null ? NULL_FIELD : value); + return getDeferredField(handler); + } + + public void enableLoggers() { + if (contextDiagnosticListener != null) { + context.put(DiagnosticListener.class, contextDiagnosticListener); + contextDiagnosticListener = null; + } + + if (errWriter != null) try { + errWriterField.set(log, errWriter); + errWriter = null; + } catch (Exception e) {} + + if (warnWriter != null) try { + warnWriterField.set(log, warnWriter); + warnWriter = null; + } catch (Exception e) {} + + if (noticeWriter != null) try { + noticeWriterField.set(log, noticeWriter); + noticeWriter = null; + } catch (Exception e) {} + + if (dumpOnError != null) try { + dumpOnErrorField.set(log, dumpOnError); + dumpOnError = null; + } catch (Exception e) {} + + if (promptOnError != null) try { + promptOnErrorField.set(log, promptOnError); + promptOnError = null; + } catch (Exception e) {} + + if (logDiagnosticListener != null) try { + diagnosticListenerField.set(log, logDiagnosticListener); + logDiagnosticListener = null; + } catch (Exception e) {} + + if (diagnosticHandlerField != null && queueCache.get() != null) try { + Object handler = diagnosticHandlerField.get(log); + Field field = getDeferredField(handler); + if (field != null) { + field.set(handler, queueCache.get()); + queueCache.set(null); + } + } catch (Exception e) {} + + if (deferDiagnosticsField != null && queueCache.get() != null) try { + deferredDiagnosticsField.set(log, queueCache.get()); + queueCache.set(null); + } catch (Exception e) {} + } + + public void removeAllBetween(JavaFileObject sourcefile, int startPos, int endPos) { + DiagnosticListener<?> listener = context.get(DiagnosticListener.class); + if (listener instanceof CapturingDiagnosticListener) { + ((CapturingDiagnosticListener) listener).suppress(startPos, endPos); + } + + Field field = null; + Object receiver = null; + if (deferDiagnosticsField != null) try { + if (Boolean.TRUE.equals(deferDiagnosticsField.get(log))) { + field = deferredDiagnosticsField; + receiver = log; + } + } catch (Exception e) {} + + if (diagnosticHandlerField != null) try { + Object handler = diagnosticHandlerField.get(log); + field = getDeferredField(handler); + receiver = handler; + } catch (Exception e) {} + + if (field == null || receiver == null) return; + + try { + ListBuffer<?> deferredDiagnostics = (ListBuffer<?>) field.get(receiver); + ListBuffer<Object> newDeferredDiagnostics = new ListBuffer<Object>(); + for (Object diag_ : deferredDiagnostics) { + if (!(diag_ instanceof JCDiagnostic)) { + newDeferredDiagnostics.add(diag_); + continue; + } + JCDiagnostic diag = (JCDiagnostic) diag_; + long here = diag.getStartPosition(); + if (here >= startPos && here < endPos && diag.getSource() == sourcefile) { + // We eliminate it + } else { + newDeferredDiagnostics.add(diag); + } + } + field.set(receiver, newDeferredDiagnostics); + } catch (Exception e) { + // We do not expect failure here; if failure does occur, the best course of action is to silently continue; the result will be that the error output of + // javac will contain rather a lot of messages, but this is a lot better than just crashing during compilation! + } + } +}
\ No newline at end of file diff --git a/src/core/lombok/javac/FindTypeVarScanner.java b/src/core/lombok/javac/FindTypeVarScanner.java index b1b8e525..7c7d9d50 100644 --- a/src/core/lombok/javac/FindTypeVarScanner.java +++ b/src/core/lombok/javac/FindTypeVarScanner.java @@ -88,7 +88,7 @@ public class FindTypeVarScanner extends AbstractTypeVisitor6<Void, Void> { @Override public Void visitTypeVariable(TypeVariable t, Void p) { Name name = null; try { - name = ((Type)t).tsym.name; + name = ((Type) t).tsym.name; } catch (NullPointerException e) {} if (name != null) typeVariables.add(name.toString()); subVisit(t.getLowerBound()); diff --git a/src/core/lombok/javac/Javac6BasedLombokOptions.java b/src/core/lombok/javac/Javac6BasedLombokOptions.java new file mode 100644 index 00000000..871e41c4 --- /dev/null +++ b/src/core/lombok/javac/Javac6BasedLombokOptions.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 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 + * 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; + +import com.sun.tools.javac.main.OptionName; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; + +public class Javac6BasedLombokOptions extends LombokOptions { + public static Javac6BasedLombokOptions replaceWithDelombokOptions(Context context) { + Options options = Options.instance(context); + context.put(optionsKey, (Options)null); + Javac6BasedLombokOptions result = new Javac6BasedLombokOptions(context); + result.putAll(options); + return result; + } + + private Javac6BasedLombokOptions(Context context) { + super(context); + } + + @Override public void putJavacOption(String optionName, String value) { + put(OptionName.valueOf(optionName), value); + } +} diff --git a/src/core/lombok/javac/Javac8BasedLombokOptions.java b/src/core/lombok/javac/Javac8BasedLombokOptions.java new file mode 100644 index 00000000..3fdea890 --- /dev/null +++ b/src/core/lombok/javac/Javac8BasedLombokOptions.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013 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 + * 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; + +import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; + +public class Javac8BasedLombokOptions extends LombokOptions { + public static Javac8BasedLombokOptions replaceWithDelombokOptions(Context context) { + Options options = Options.instance(context); + context.put(optionsKey, (Options)null); + Javac8BasedLombokOptions result = new Javac8BasedLombokOptions(context); + result.putAll(options); + return result; + } + + private Javac8BasedLombokOptions(Context context) { + super(context); + } + + @Override public void putJavacOption(String optionName, String value) { + String optionText = Option.valueOf(optionName).text; + put(optionText, value); + } +} diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 36c51210..31bdc3a6 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -29,7 +29,6 @@ import java.util.List; import javax.annotation.processing.Messager; import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import lombok.core.AST; @@ -53,8 +52,6 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JCDiagnostic; -import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -66,7 +63,7 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { private final Messager messager; private final JavacElements elements; - private final TreeMaker treeMaker; + private final JavacTreeMaker treeMaker; private final Symtab symtab; private final JavacTypes javacTypes; private final Log log; @@ -86,7 +83,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { this.messager = messager; this.log = Log.instance(context); this.elements = JavacElements.instance(context); - this.treeMaker = TreeMaker.instance(context); + this.treeMaker = new JavacTreeMaker(TreeMaker.instance(context)); this.symtab = Symtab.instance(context); this.javacTypes = JavacTypes.instance(context); clearChanged(); @@ -135,7 +132,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { } /** @return A TreeMaker instance that you can use to create new AST nodes. */ - public TreeMaker getTreeMaker() { + public JavacTreeMaker getTreeMaker() { treeMaker.at(-1); return treeMaker; } @@ -343,24 +340,13 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { if (node != null) nodes.add(node); } - private static final Field JAVAC7_DEFERRED_DIAGNOSTICS; - - static { - Field f = null; - try { - f = Log.class.getField("deferredDiagnostics"); - if (!ListBuffer.class.isAssignableFrom(f.getType())) throw new NoSuchFieldException("deferredDiagnostics does not have the expected type."); - } catch (NoSuchFieldException e) {} - JAVAC7_DEFERRED_DIAGNOSTICS = f; - } - /** * Attempts to remove any compiler errors generated by java whose reporting position is located anywhere between the start and end of the supplied node. */ void removeDeferredErrors(JavacNode node) { DiagnosticPosition pos = node.get().pos(); JCCompilationUnit top = (JCCompilationUnit) top().get(); - removeFromDeferredDiagnostics(pos.getStartPosition(), pos.getEndPosition(top.endPositions)); + removeFromDeferredDiagnostics(pos.getStartPosition(), Javac.getEndPosition(pos, top)); } /** Supply either a position or a node (in that case, position of the node is used) */ @@ -375,7 +361,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { if (pos == null) pos = astObject.pos(); } if (pos != null && attemptToRemoveErrorsInRange) { - removeFromDeferredDiagnostics(pos.getStartPosition(), pos.getEndPosition(top.endPositions)); + removeFromDeferredDiagnostics(pos.getStartPosition(), node.getEndPosition(pos)); } try { switch (kind) { @@ -400,32 +386,8 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { } private void removeFromDeferredDiagnostics(int startPos, int endPos) { - DiagnosticListener<?> listener = getContext().get(DiagnosticListener.class); - if (listener instanceof CapturingDiagnosticListener) { - ((CapturingDiagnosticListener) listener).suppress(startPos, endPos); - } - try { - if (JAVAC7_DEFERRED_DIAGNOSTICS != null) { - ListBuffer<?> deferredDiagnostics = (ListBuffer<?>) JAVAC7_DEFERRED_DIAGNOSTICS.get(log); - ListBuffer<Object> newDeferredDiagnostics = ListBuffer.lb(); - for (Object diag : deferredDiagnostics) { - if (!(diag instanceof JCDiagnostic)) { - newDeferredDiagnostics.add(diag); - continue; - } - long here = ((JCDiagnostic) diag).getStartPosition(); - if (here >= startPos && here < endPos) { - // We eliminate it - } else { - newDeferredDiagnostics.add(diag); - } - } - JAVAC7_DEFERRED_DIAGNOSTICS.set(log, newDeferredDiagnostics); - } - } catch (Exception e) { - // We do not expect failure here; if failure does occur, the best course of action is to silently continue; the result will be that the error output of - // javac will contain rather a lot of messages, but this is a lot better than just crashing during compilation! - } + JCCompilationUnit self = (JCCompilationUnit) top().get(); + new CompilerMessageSuppressor(getContext()).removeAllBetween(self.sourcefile, startPos, endPos); } /** {@inheritDoc} */ diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index 16c06430..6eef36eb 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -30,7 +30,6 @@ import lombok.core.AST.Kind; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.model.JavacTypes; 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.JCBlock; import com.sun.tools.javac.tree.JCTree.JCClassDecl; @@ -52,6 +51,15 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre super(ast, node, children, kind); } + public int getEndPosition(DiagnosticPosition pos) { + JCCompilationUnit cu = (JCCompilationUnit) top().get(); + return Javac.getEndPosition(pos, cu); + } + + public int getEndPosition() { + return getEndPosition(node); + } + /** * Visits this node and all child nodes depth-first, calling the provided visitor's visit methods. */ @@ -165,7 +173,7 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre * * @see JavacAST#getTreeMaker() */ - public TreeMaker getTreeMaker() { + public JavacTreeMaker getTreeMaker() { return ast.getTreeMaker(); } diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index 0a21aa58..5631e62c 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 The Project Lombok Authors. + * Copyright (C) 2011-2013 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 @@ -22,18 +22,12 @@ package lombok.javac; import static lombok.javac.Javac.*; +import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.lang.reflect.Field; import java.util.ArrayDeque; -import java.util.LinkedList; import java.util.Map; -import java.util.Queue; import javax.lang.model.type.TypeKind; -import javax.tools.DiagnosticListener; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Symbol.TypeSymbol; @@ -43,7 +37,6 @@ import com.sun.tools.javac.code.Type.ArrayType; import com.sun.tools.javac.code.Type.CapturedType; import com.sun.tools.javac.code.Type.ClassType; import com.sun.tools.javac.code.Type.WildcardType; -import com.sun.tools.javac.code.TypeTags; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.AttrContext; @@ -57,191 +50,17 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Log; public class JavacResolution { private final Attr attr; - private final LogDisabler logDisabler; + private final CompilerMessageSuppressor messageSuppressor; public JavacResolution(Context context) { attr = Attr.instance(context); - logDisabler = new LogDisabler(context); - } - - /** - * During resolution, the resolver will emit resolution errors, but without appropriate file names and line numbers. If these resolution errors stick around - * then they will be generated AGAIN, this time with proper names and line numbers, at the end. Therefore, we want to suppress the logger. - */ - private static final class LogDisabler { - private final Log log; - private static final Field errWriterField, warnWriterField, noticeWriterField, dumpOnErrorField, promptOnErrorField, diagnosticListenerField; - private static final Field deferDiagnosticsField, deferredDiagnosticsField; - private PrintWriter errWriter, warnWriter, noticeWriter; - private Boolean dumpOnError, promptOnError; - private DiagnosticListener<?> contextDiagnosticListener, logDiagnosticListener; - private final Context context; - - // If this is true, the fields changed. Better to print weird error messages than to fail outright. - private static final boolean dontBother; - - private static final ThreadLocal<Queue<?>> queueCache = new ThreadLocal<Queue<?>>(); - - static { - boolean z; - Field a = null, b = null, c = null, d = null, e = null, f = null, g = null, h = null; - try { - a = Log.class.getDeclaredField("errWriter"); - b = Log.class.getDeclaredField("warnWriter"); - c = Log.class.getDeclaredField("noticeWriter"); - d = Log.class.getDeclaredField("dumpOnError"); - e = Log.class.getDeclaredField("promptOnError"); - f = Log.class.getDeclaredField("diagListener"); - z = false; - a.setAccessible(true); - b.setAccessible(true); - c.setAccessible(true); - d.setAccessible(true); - e.setAccessible(true); - f.setAccessible(true); - } catch (Throwable x) { - z = true; - } - - try { - g = Log.class.getDeclaredField("deferDiagnostics"); - h = Log.class.getDeclaredField("deferredDiagnostics"); - g.setAccessible(true); - h.setAccessible(true); - } catch (Throwable x) { - } - - errWriterField = a; - warnWriterField = b; - noticeWriterField = c; - dumpOnErrorField = d; - promptOnErrorField = e; - diagnosticListenerField = f; - deferDiagnosticsField = g; - deferredDiagnosticsField = h; - dontBother = z; - } - - LogDisabler(Context context) { - this.log = Log.instance(context); - this.context = context; - } - - boolean disableLoggers() { - contextDiagnosticListener = context.get(DiagnosticListener.class); - context.put(DiagnosticListener.class, (DiagnosticListener<?>) null); - if (dontBother) return false; - boolean dontBotherInstance = false; - - PrintWriter dummyWriter = new PrintWriter(new OutputStream() { - @Override public void write(int b) throws IOException { - // Do nothing on purpose - } - }); - - if (deferDiagnosticsField != null) try { - if (Boolean.TRUE.equals(deferDiagnosticsField.get(log))) { - queueCache.set((Queue<?>) deferredDiagnosticsField.get(log)); - Queue<?> empty = new LinkedList<Object>(); - deferredDiagnosticsField.set(log, empty); - } - } catch (Exception e) {} - - if (!dontBotherInstance) try { - errWriter = (PrintWriter) errWriterField.get(log); - errWriterField.set(log, dummyWriter); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - warnWriter = (PrintWriter) warnWriterField.get(log); - warnWriterField.set(log, dummyWriter); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - noticeWriter = (PrintWriter) noticeWriterField.get(log); - noticeWriterField.set(log, dummyWriter); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - dumpOnError = (Boolean) dumpOnErrorField.get(log); - dumpOnErrorField.set(log, false); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - promptOnError = (Boolean) promptOnErrorField.get(log); - promptOnErrorField.set(log, false); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - logDiagnosticListener = (DiagnosticListener<?>) diagnosticListenerField.get(log); - diagnosticListenerField.set(log, null); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (dontBotherInstance) enableLoggers(); - return !dontBotherInstance; - } - - void enableLoggers() { - if (contextDiagnosticListener != null) { - context.put(DiagnosticListener.class, contextDiagnosticListener); - contextDiagnosticListener = null; - } - - if (errWriter != null) try { - errWriterField.set(log, errWriter); - errWriter = null; - } catch (Exception e) {} - - if (warnWriter != null) try { - warnWriterField.set(log, warnWriter); - warnWriter = null; - } catch (Exception e) {} - - if (noticeWriter != null) try { - noticeWriterField.set(log, noticeWriter); - noticeWriter = null; - } catch (Exception e) {} - - if (dumpOnError != null) try { - dumpOnErrorField.set(log, dumpOnError); - dumpOnError = null; - } catch (Exception e) {} - - if (promptOnError != null) try { - promptOnErrorField.set(log, promptOnError); - promptOnError = null; - } catch (Exception e) {} - - if (logDiagnosticListener != null) try { - diagnosticListenerField.set(log, logDiagnosticListener); - logDiagnosticListener = null; - } catch (Exception e) {} - - if (deferDiagnosticsField != null && queueCache.get() != null) try { - deferredDiagnosticsField.set(log, queueCache.get()); - queueCache.set(null); - } catch (Exception e) {} - } + messageSuppressor = new CompilerMessageSuppressor(context); } /* @@ -321,7 +140,7 @@ public class JavacResolution { } } - logDisabler.disableLoggers(); + messageSuppressor.disableLoggers(); try { EnvFinder finder = new EnvFinder(node.getContext()); while (!stack.isEmpty()) stack.pop().accept(finder); @@ -332,7 +151,7 @@ public class JavacResolution { attrib(copy, finder.get()); return mirrorMaker.getOriginalToCopyMap(); } finally { - logDisabler.enableLoggers(); + messageSuppressor.enableLoggers(); } } @@ -347,14 +166,14 @@ public class JavacResolution { } } - logDisabler.disableLoggers(); + messageSuppressor.disableLoggers(); try { EnvFinder finder = new EnvFinder(node.getContext()); while (!stack.isEmpty()) stack.pop().accept(finder); attrib(node.get(), finder.get()); } finally { - logDisabler.enableLoggers(); + messageSuppressor.enableLoggers(); } } @@ -390,7 +209,7 @@ public class JavacResolution { } public static JCExpression createJavaLangObject(JavacAST ast) { - TreeMaker maker = ast.getTreeMaker(); + JavacTreeMaker maker = ast.getTreeMaker(); JCExpression out = maker.Ident(ast.toName("java")); out = maker.Select(out, ast.toName("lang")); out = maker.Select(out, ast.toName("Object")); @@ -417,10 +236,10 @@ public class JavacResolution { // NB: There's such a thing as maker.Type(type), but this doesn't work very well; it screws up anonymous classes, captures, and adds an extra prefix dot for some reason too. // -- so we write our own take on that here. - TreeMaker maker = ast.getTreeMaker(); + JavacTreeMaker maker = ast.getTreeMaker(); - if (type.tag == CTC_BOT) return createJavaLangObject(ast); - if (type.tag == CTC_VOID) return allowVoid ? primitiveToJCTree(type.getKind(), maker) : createJavaLangObject(ast); + if (CTC_BOT.equals(typeTag(type))) return createJavaLangObject(ast); + if (CTC_VOID.equals(typeTag(type))) return allowVoid ? primitiveToJCTree(type.getKind(), maker) : createJavaLangObject(ast); if (type.isPrimitive()) return primitiveToJCTree(type.getKind(), maker); if (type.isErroneous()) throw new TypeNotConvertibleException("Type cannot be resolved"); @@ -434,8 +253,8 @@ public class JavacResolution { if (symbol.name.length() == 0) { // Anonymous inner class if (type instanceof ClassType) { - List<Type> ifaces = ((ClassType)type).interfaces_field; - Type supertype = ((ClassType)type).supertype_field; + List<Type> ifaces = ((ClassType) type).interfaces_field; + Type supertype = ((ClassType) type).supertype_field; if (ifaces != null && ifaces.length() == 1) { return typeToJCTree(ifaces.get(0), ast, allowCompound, allowVoid); } @@ -454,7 +273,7 @@ public class JavacResolution { upper = type.getUpperBound(); } if (allowCompound) { - if (lower == null || lower.tag == CTC_BOT) { + if (lower == null || CTC_BOT.equals(typeTag(lower))) { if (upper == null || upper.toString().equals("java.lang.Object")) { return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); } @@ -479,7 +298,7 @@ public class JavacResolution { String qName; if (symbol.isLocal()) { qName = symbol.getSimpleName().toString(); - } else if (symbol.type != null && symbol.type.getEnclosingType() != null && symbol.type.getEnclosingType().tag == TypeTags.CLASS) { + } else if (symbol.type != null && symbol.type.getEnclosingType() != null && typeTag(symbol.type.getEnclosingType()).equals(typeTag("CLASS"))) { replacement = typeToJCTree0(type.getEnclosingType(), ast, false, false); qName = symbol.getSimpleName().toString(); } else { @@ -504,7 +323,7 @@ public class JavacResolution { private static JCExpression genericsToJCTreeNodes(List<Type> generics, JavacAST ast, JCExpression rawTypeNode) throws TypeNotConvertibleException { if (generics != null && !generics.isEmpty()) { - ListBuffer<JCExpression> args = ListBuffer.lb(); + ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); for (Type t : generics) args.append(typeToJCTree(t, ast, true, false)); return ast.getTreeMaker().TypeApply(rawTypeNode, args.toList()); } @@ -512,12 +331,12 @@ public class JavacResolution { return rawTypeNode; } - private static JCExpression primitiveToJCTree(TypeKind kind, TreeMaker maker) throws TypeNotConvertibleException { + private static JCExpression primitiveToJCTree(TypeKind kind, JavacTreeMaker maker) throws TypeNotConvertibleException { switch (kind) { case BYTE: return maker.TypeIdent(CTC_BYTE); case CHAR: - return maker.TypeIdent(CTC_CHAR); + return maker.TypeIdent( CTC_CHAR); case SHORT: return maker.TypeIdent(CTC_SHORT); case INT: diff --git a/src/core/lombok/javac/LombokOptions.java b/src/core/lombok/javac/LombokOptions.java index 1a73a8cc..f1567e9d 100644 --- a/src/core/lombok/javac/LombokOptions.java +++ b/src/core/lombok/javac/LombokOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Project Lombok Authors. + * Copyright (C) 2010-2013 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 @@ -28,18 +28,10 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Options; -public class LombokOptions extends Options { +public abstract class LombokOptions extends Options { private boolean deleteLombokAnnotations = true; private final Set<JCCompilationUnit> changed = new HashSet<JCCompilationUnit>(); - public static LombokOptions replaceWithDelombokOptions(Context context) { - Options options = Options.instance(context); - context.put(optionsKey, (Options)null); - LombokOptions result = new LombokOptions(context); - result.putAll(options); - return result; - } - public boolean isChanged(JCCompilationUnit ast) { return changed.contains(ast); } @@ -54,7 +46,9 @@ public class LombokOptions extends Options { return (options instanceof LombokOptions) && ((LombokOptions) options).deleteLombokAnnotations; } - private LombokOptions(Context context) { + protected LombokOptions(Context context) { super(context); } + + public abstract void putJavacOption(String optionName, String value); } diff --git a/src/core/lombok/javac/apt/Processor.java b/src/core/lombok/javac/apt/Processor.java index 110acaad..5f28aa88 100644 --- a/src/core/lombok/javac/apt/Processor.java +++ b/src/core/lombok/javac/apt/Processor.java @@ -210,6 +210,7 @@ public class Processor extends AbstractProcessor { Field f = JavacProcessingEnvironment.class.getDeclaredField("processorClassLoader"); f.setAccessible(true); ClassLoader unwrapped = (ClassLoader) f.get(processingEnv); + if (unwrapped == null) return; ClassLoader wrapped = new WrappingClassLoader(unwrapped); f.set(processingEnv, wrapped); } catch (NoSuchFieldException e) { diff --git a/src/core/lombok/javac/handlers/HandleAccessors.java b/src/core/lombok/javac/handlers/HandleAccessors.java index 7aeec6bb..e2489bda 100644 --- a/src/core/lombok/javac/handlers/HandleAccessors.java +++ b/src/core/lombok/javac/handlers/HandleAccessors.java @@ -28,11 +28,13 @@ import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.experimental.Accessors; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; @ProviderFor(JavacAnnotationHandler.class) +@HandlerPriority(65536) public class HandleAccessors extends JavacAnnotationHandler<Accessors> { @Override public void handle(AnnotationValues<Accessors> annotation, JCAnnotation ast, JavacNode annotationNode) { // Accessors itself is handled by HandleGetter/Setter; this is just to ensure that the annotation is removed diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 6422f5ed..8a826087 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -41,7 +41,6 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -55,10 +54,12 @@ import lombok.experimental.Builder; import lombok.experimental.NonFinal; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; -import static lombok.javac.Javac.*; import static lombok.core.handlers.HandlerUtil.*; import static lombok.javac.handlers.JavacHandlerUtil.*; +import static lombok.javac.Javac.*; +import static lombok.javac.JavacTreeMaker.TypeTag.*; @ProviderFor(JavacAnnotationHandler.class) @HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes. @@ -97,7 +98,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { if (parent.get() instanceof JCClassDecl) { tdParent = parent; JCClassDecl td = (JCClassDecl) tdParent.get(); - ListBuffer<JavacNode> allFields = ListBuffer.lb(); + ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>(); @SuppressWarnings("deprecation") boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent)); for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent)) { @@ -106,7 +107,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { // non-final fields final, but @Value's handler hasn't done this yet, so we have to do this math ourselves. // Value will only skip making a field final if it has an explicit @NonFinal annotation, so we check for that. if (fd.init != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue; - namesOfParameters.add(fd.name); + namesOfParameters.add(removePrefixFromField(fieldNode)); typesOfParameters.add(fd.vartype); allFields.append(fieldNode); } @@ -218,12 +219,12 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } private JCMethodDecl generateBuildMethod(String name, Name staticName, JCExpression returnType, java.util.List<Name> fieldNames, JavacNode type, List<JCExpression> thrownExceptions) { - TreeMaker maker = type.getTreeMaker(); + JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; JCStatement statement; - ListBuffer<JCExpression> args = ListBuffer.lb(); + ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); for (Name n : fieldNames) { args.append(maker.Ident(n)); } @@ -232,14 +233,14 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { call = maker.NewClass(null, List.<JCExpression>nil(), returnType, args.toList(), null); statement = maker.Return(call); } else { - ListBuffer<JCExpression> typeParams = ListBuffer.lb(); + ListBuffer<JCExpression> typeParams = new ListBuffer<JCExpression>(); for (JCTypeParameter tp : ((JCClassDecl) type.get()).typarams) { typeParams.append(maker.Ident(tp.name)); } JCExpression fn = maker.Select(maker.Ident(((JCClassDecl) type.up().get()).name), staticName); call = maker.Apply(typeParams.toList(), fn, args.toList()); - if (returnType instanceof JCPrimitiveTypeTree && ((JCPrimitiveTypeTree) returnType).typetag == CTC_VOID) { + if (returnType instanceof JCPrimitiveTypeTree && CTC_VOID.equals(typeTag(returnType))) { statement = maker.Exec(call); } else { statement = maker.Return(call); @@ -252,9 +253,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } private JCMethodDecl generateBuilderMethod(String builderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams) { - TreeMaker maker = type.getTreeMaker(); + JavacTreeMaker maker = type.getTreeMaker(); - ListBuffer<JCExpression> typeArgs = ListBuffer.lb(); + ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); for (JCTypeParameter typeParam : typeParams) { typeArgs.append(maker.Ident(typeParam.name)); } @@ -285,7 +286,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { continue top; } } - TreeMaker maker = builderType.getTreeMaker(); + JavacTreeMaker maker = builderType.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.PRIVATE); JCVariableDecl newField = maker.VarDef(mods, name, cloneType(maker, typesOfParameters.get(i), source), null); out.add(injectField(builderType, newField)); @@ -308,7 +309,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { boolean isBoolean = isBoolean(fieldNode); String setterName = fluent ? fieldNode.getName() : TransformationsUtil.toSetterName(null, fieldNode.getName(), isBoolean); - TreeMaker maker = builderType.getTreeMaker(); + JavacTreeMaker maker = builderType.getTreeMaker(); return HandleSetter.createSetter(Flags.PUBLIC, fieldNode, maker, setterName, chain, source, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); } @@ -322,9 +323,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } private JavacNode makeBuilderClass(JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast) { - TreeMaker maker = tdParent.getTreeMaker(); + JavacTreeMaker maker = tdParent.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.PUBLIC | Flags.STATIC); - JCClassDecl builder = ClassDef(maker, mods, tdParent.toName(builderClassName), copyTypeParams(maker, typeParams), null, List.<JCExpression>nil(), List.<JCTree>nil()); + JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderClassName), copyTypeParams(maker, typeParams), null, List.<JCExpression>nil(), List.<JCTree>nil()); return injectType(tdParent, builder); } } diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java index 09b4faee..e7786ffe 100644 --- a/src/core/lombok/javac/handlers/HandleCleanup.java +++ b/src/core/lombok/javac/handlers/HandleCleanup.java @@ -28,10 +28,10 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; 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.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCAssign; @@ -49,7 +49,6 @@ import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -97,8 +96,8 @@ public class HandleCleanup extends JavacAnnotationHandler<Cleanup> { } boolean seenDeclaration = false; - ListBuffer<JCStatement> newStatements = ListBuffer.lb(); - ListBuffer<JCStatement> tryBlock = ListBuffer.lb(); + ListBuffer<JCStatement> newStatements = new ListBuffer<JCStatement>(); + ListBuffer<JCStatement> tryBlock = new ListBuffer<JCStatement>(); for (JCStatement statement : statements) { if (!seenDeclaration) { if (statement == decl) seenDeclaration = true; @@ -114,7 +113,7 @@ public class HandleCleanup extends JavacAnnotationHandler<Cleanup> { } doAssignmentCheck(annotationNode, tryBlock.toList(), decl.name); - TreeMaker maker = annotationNode.getTreeMaker(); + JavacTreeMaker maker = annotationNode.getTreeMaker(); 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()))); @@ -139,9 +138,9 @@ public class HandleCleanup extends JavacAnnotationHandler<Cleanup> { ancestor.rebuild(); } - private JCMethodInvocation preventNullAnalysis(TreeMaker maker, JavacNode node, JCExpression expression) { + private JCMethodInvocation preventNullAnalysis(JavacTreeMaker maker, JavacNode node, JCExpression expression) { JCMethodInvocation singletonList = maker.Apply(List.<JCExpression>nil(), chainDotsString(node, "java.util.Collections.singletonList"), List.of(expression)); - JCMethodInvocation cleanedExpr = maker.Apply(List.<JCExpression>nil(), maker.Select(singletonList, node.toName("get")) , List.<JCExpression>of(maker.Literal(TypeTags.INT, 0))); + JCMethodInvocation cleanedExpr = maker.Apply(List.<JCExpression>nil(), maker.Select(singletonList, node.toName("get")) , List.<JCExpression>of(maker.Literal(CTC_INT, 0))); return cleanedExpr; } diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index ecd982e9..b77a5367 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -32,12 +32,12 @@ import lombok.core.AST.Kind; import lombok.experimental.Builder; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; 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.JCBlock; @@ -52,6 +52,7 @@ import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Name; public class HandleConstructor { @ProviderFor(JavacAnnotationHandler.class) @@ -90,7 +91,7 @@ public class HandleConstructor { } private static List<JavacNode> findRequiredFields(JavacNode typeNode) { - ListBuffer<JavacNode> fields = ListBuffer.lb(); + ListBuffer<JavacNode> fields = new ListBuffer<JavacNode>(); for (JavacNode child : typeNode.down()) { if (child.getKind() != Kind.FIELD) continue; JCVariableDecl fieldDecl = (JCVariableDecl) child.get(); @@ -125,7 +126,7 @@ public class HandleConstructor { } static List<JavacNode> findAllFields(JavacNode typeNode) { - ListBuffer<JavacNode> fields = ListBuffer.lb(); + ListBuffer<JavacNode> fields = new ListBuffer<JavacNode>(); for (JavacNode child : typeNode.down()) { if (child.getKind() != Kind.FIELD) continue; JCVariableDecl fieldDecl = (JCVariableDecl) child.get(); @@ -206,11 +207,12 @@ public class HandleConstructor { private static void addConstructorProperties(JCModifiers mods, JavacNode node, List<JavacNode> fields) { if (fields.isEmpty()) return; - TreeMaker maker = node.getTreeMaker(); + JavacTreeMaker maker = node.getTreeMaker(); JCExpression constructorPropertiesType = chainDots(node, "java", "beans", "ConstructorProperties"); - ListBuffer<JCExpression> fieldNames = ListBuffer.lb(); + ListBuffer<JCExpression> fieldNames = new ListBuffer<JCExpression>(); for (JavacNode field : fields) { - fieldNames.append(maker.Literal(field.getName())); + Name fieldName = removePrefixFromField(field); + fieldNames.append(maker.Literal(fieldName.toString())); } JCExpression fieldNamesArray = maker.NewArray(null, List.<JCExpression>nil(), fieldNames.toList()); JCAnnotation annotation = maker.Annotation(constructorPropertiesType, List.of(fieldNamesArray)); @@ -218,23 +220,25 @@ public class HandleConstructor { } static JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, boolean suppressConstructorProperties, JCTree source) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0; if (isEnum) level = AccessLevel.PRIVATE; - ListBuffer<JCStatement> nullChecks = ListBuffer.lb(); - ListBuffer<JCStatement> assigns = ListBuffer.lb(); - ListBuffer<JCVariableDecl> params = ListBuffer.lb(); + ListBuffer<JCStatement> nullChecks = new ListBuffer<JCStatement>(); + ListBuffer<JCStatement> assigns = new ListBuffer<JCStatement>(); + ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); for (JavacNode fieldNode : fields) { JCVariableDecl field = (JCVariableDecl) fieldNode.get(); + Name fieldName = removePrefixFromField(fieldNode); + Name rawName = field.name; List<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN); List<JCAnnotation> nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN); - JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables)), field.name, field.vartype, null); + JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER, nonNulls.appendList(nullables)), fieldName, field.vartype, null); params.append(param); - JCFieldAccess thisX = maker.Select(maker.Ident(fieldNode.toName("this")), field.name); - JCAssign assign = maker.Assign(thisX, maker.Ident(field.name)); + JCFieldAccess thisX = maker.Select(maker.Ident(fieldNode.toName("this")), rawName); + JCAssign assign = maker.Assign(thisX, maker.Ident(fieldName)); assigns.append(maker.Exec(assign)); if (!nonNulls.isEmpty()) { @@ -261,18 +265,18 @@ public class HandleConstructor { } private JCMethodDecl createStaticConstructor(String name, AccessLevel level, JavacNode typeNode, List<JavacNode> fields, JCTree source) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); JCClassDecl type = (JCClassDecl) typeNode.get(); JCModifiers mods = maker.Modifiers(Flags.STATIC | toJavacModifier(level)); JCExpression returnType, constructorType; - ListBuffer<JCTypeParameter> typeParams = ListBuffer.lb(); - ListBuffer<JCVariableDecl> params = ListBuffer.lb(); - ListBuffer<JCExpression> typeArgs1 = ListBuffer.lb(); - ListBuffer<JCExpression> typeArgs2 = ListBuffer.lb(); - ListBuffer<JCExpression> args = ListBuffer.lb(); + ListBuffer<JCTypeParameter> typeParams = new ListBuffer<JCTypeParameter>(); + ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); + ListBuffer<JCExpression> typeArgs1 = new ListBuffer<JCExpression>(); + ListBuffer<JCExpression> typeArgs2 = new ListBuffer<JCExpression>(); + ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); if (!type.typarams.isEmpty()) { for (JCTypeParameter param : type.typarams) { @@ -289,12 +293,13 @@ public class HandleConstructor { for (JavacNode fieldNode : fields) { JCVariableDecl field = (JCVariableDecl) fieldNode.get(); + Name fieldName = removePrefixFromField(fieldNode); JCExpression pType = cloneType(maker, field.vartype, source); List<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN); List<JCAnnotation> nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN); - JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables)), field.name, pType, null); + JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER, nonNulls.appendList(nullables)), fieldName, pType, null); params.append(param); - args.append(maker.Ident(field.name)); + args.append(maker.Ident(fieldName)); } JCReturn returnStatement = maker.Return(maker.NewClass(null, List.<JCExpression>nil(), constructorType, args.toList(), null)); JCBlock body = maker.Block(0, List.<JCStatement>of(returnStatement)); diff --git a/src/core/lombok/javac/handlers/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java index 644b03fb..6af34f20 100644 --- a/src/core/lombok/javac/handlers/HandleDelegate.java +++ b/src/core/lombok/javac/handlers/HandleDelegate.java @@ -48,6 +48,7 @@ import lombok.javac.FindTypeVarScanner; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacResolution; +import lombok.javac.JavacTreeMaker; import lombok.javac.ResolutionResetNeeded; import lombok.javac.JavacResolution.TypeNotConvertibleException; @@ -71,7 +72,6 @@ import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -266,7 +266,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { checkConflictOfTypeVarNames(sig, annotation); - TreeMaker maker = annotation.getTreeMaker(); + JavacTreeMaker maker = annotation.getTreeMaker(); com.sun.tools.javac.util.List<JCAnnotation> annotations; if (sig.isDeprecated) { @@ -305,7 +305,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { int idx = 0; for (TypeMirror param : sig.type.getParameterTypes()) { - JCModifiers paramMods = maker.Modifiers(Flags.FINAL); + JCModifiers paramMods = maker.Modifiers(Flags.FINAL | Flags.PARAMETER); String[] paramNames = sig.getParameterNames(); Name name = annotation.toName(paramNames[idx++]); params.append(maker.VarDef(paramMods, name, JavacResolution.typeToJCTree((Type) param, annotation.getAst(), true), null)); @@ -394,13 +394,13 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { METHOD { public JCExpression get(final JavacNode node, final Name name) { com.sun.tools.javac.util.List<JCExpression> nilExprs = com.sun.tools.javac.util.List.nil(); - final TreeMaker maker = node.getTreeMaker(); + final JavacTreeMaker maker = node.getTreeMaker(); return maker.Apply(nilExprs, maker.Select(maker.Ident(node.toName("this")), name), nilExprs); } }, FIELD { public JCExpression get(final JavacNode node, final Name name) { - final TreeMaker maker = node.getTreeMaker(); + final JavacTreeMaker maker = node.getTreeMaker(); return maker.Select(maker.Ident(node.toName("this")), name); } }; diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index 3b1e226f..0f8161e1 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -31,8 +31,10 @@ import java.util.Collections; import lombok.EqualsAndHashCode; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; @@ -40,7 +42,6 @@ import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.TypeTags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; @@ -57,7 +58,6 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCUnary; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -139,7 +139,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } } - JCTree extending = ((JCClassDecl)typeNode.get()).getExtendsClause(); + JCTree extending = Javac.getExtendsClause((JCClassDecl)typeNode.get()); if (extending != null) { String p = extending.toString(); isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object"); @@ -154,7 +154,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas source.addWarning("Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type."); } - ListBuffer<JavacNode> nodesForEquality = ListBuffer.lb(); + ListBuffer<JavacNode> nodesForEquality = new ListBuffer<JavacNode>(); if (includes != null) { for (JavacNode child : typeNode.down()) { if (child.getKind() != Kind.FIELD) continue; @@ -195,7 +195,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas // The user code couldn't possibly (barring really weird subclassing shenanigans) be in a shippable state anyway; the implementations of these 3 methods are // all inter-related and should be written by the same entity. String msg = String.format("Not generating %s: One of equals, hashCode, and canEqual exists. " + - "You should either write all of these are none of these (in the latter case, lombok generates them).", + "You should either write all of these or none of these (in the latter case, lombok generates them).", equalsExists == MemberExistsResult.NOT_EXISTS && hashCodeExists == MemberExistsResult.NOT_EXISTS ? "equals and hashCode" : equalsExists == MemberExistsResult.NOT_EXISTS ? "equals" : "hashCode"); source.addWarning(msg); @@ -219,12 +219,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } private JCMethodDecl createHashCode(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, JCTree source) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(chainDots(typeNode, "java", "lang", "Override"), List.<JCExpression>nil()); JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); JCExpression returnType = maker.TypeIdent(CTC_INT); - ListBuffer<JCStatement> statements = ListBuffer.lb(); + ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); Name primeName = typeNode.toName(PRIME_NAME); Name resultName = typeNode.toName(RESULT_NAME); @@ -258,7 +258,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas break; case LONG: { Name dollarFieldName = dollar.append(((JCVariableDecl)fieldNode.get()).name); - statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), dollarFieldName, maker.TypeIdent(TypeTags.LONG), fieldAccessor)); + statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), dollarFieldName, maker.TypeIdent(CTC_LONG), fieldAccessor)); statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName)))); } break; @@ -276,7 +276,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas List.<JCExpression>nil(), chainDots(typeNode, "java", "lang", "Double", "doubleToLongBits"), List.of(fieldAccessor)); - statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), dollarFieldName, maker.TypeIdent(TypeTags.LONG), init)); + statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), dollarFieldName, maker.TypeIdent(CTC_LONG), init)); statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName)))); } break; @@ -322,7 +322,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas private JCExpressionStatement createResultCalculation(JavacNode typeNode, JCExpression expr) { /* result = result * PRIME + (expr); */ - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); Name resultName = typeNode.toName(RESULT_NAME); JCExpression mult = maker.Binary(CTC_MUL, maker.Ident(resultName), maker.Ident(typeNode.toName(PRIME_NAME))); JCExpression add = maker.Binary(CTC_PLUS, mult, expr); @@ -330,7 +330,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } /** The 2 references must be clones of each other. */ - private JCExpression longToIntForHashCode(TreeMaker maker, JCExpression ref1, JCExpression ref2) { + private JCExpression longToIntForHashCode(JavacTreeMaker maker, JCExpression ref1, JCExpression ref2) { /* (int)(ref >>> 32 ^ ref) */ JCExpression shift = maker.Binary(CTC_UNSIGNED_SHIFT_RIGHT, ref1, maker.Literal(32)); JCExpression xorBits = maker.Binary(CTC_BITXOR, shift, ref2); @@ -347,7 +347,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } Collections.reverse(list); - TreeMaker maker = type.getTreeMaker(); + JavacTreeMaker maker = type.getTreeMaker(); JCExpression chain = maker.Ident(type.toName(list.get(0))); for (int i = 1; i < list.size(); i++) { @@ -358,7 +358,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } private JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); JCClassDecl type = (JCClassDecl) typeNode.get(); Name oName = typeNode.toName("o"); @@ -370,8 +370,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas JCExpression objectType = chainDots(typeNode, "java", "lang", "Object"); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); - ListBuffer<JCStatement> statements = ListBuffer.lb(); - final List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(Flags.FINAL), oName, objectType, null)); + ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); + final List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER), oName, objectType, null)); /* if (o == this) return true; */ { statements.append(maker.If(maker.Binary(CTC_EQUAL, maker.Ident(oName), @@ -379,6 +379,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } /* if (!(o instanceof Outer.Inner.MyType) return false; */ { + JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode))); statements.append(maker.If(notInstanceOf, returnBool(maker, false), null)); } @@ -386,8 +387,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas /* MyType<?> other = (MyType<?>) o; */ { if (!fields.isEmpty() || needsCanEqual) { final JCExpression selfType1, selfType2; - ListBuffer<JCExpression> wildcards1 = ListBuffer.lb(); - ListBuffer<JCExpression> wildcards2 = ListBuffer.lb(); + ListBuffer<JCExpression> wildcards1 = new ListBuffer<JCExpression>(); + ListBuffer<JCExpression> wildcards2 = new ListBuffer<JCExpression>(); for (int i = 0 ; i < type.typarams.length() ; i++) { wildcards1.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); wildcards2.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); @@ -493,14 +494,14 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas * return other instanceof Outer.Inner.MyType; * } */ - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.<JCAnnotation>nil()); JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN); Name canEqualName = typeNode.toName("canEqual"); JCExpression objectType = chainDots(typeNode, "java", "lang", "Object"); Name otherName = typeNode.toName("other"); - List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(Flags.FINAL), otherName, objectType, null)); + List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER), otherName, objectType, null)); JCBlock body = maker.Block(0, List.<JCStatement>of( maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode))))); @@ -509,7 +510,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } private JCStatement generateCompareFloatOrDouble(JCExpression thisDotField, JCExpression otherDotField, - TreeMaker maker, JavacNode node, boolean isDouble) { + JavacTreeMaker maker, JavacNode node, boolean isDouble) { /* if (Float.compare(fieldName, other.fieldName) != 0) return false; */ JCExpression clazz = chainDots(node, "java", "lang", isDouble ? "Double" : "Float"); List<JCExpression> args = List.of(thisDotField, otherDotField); @@ -518,7 +519,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas return maker.If(compareCallEquals0, returnBool(maker, false), null); } - private JCStatement returnBool(TreeMaker maker, boolean bool) { + private JCStatement returnBool(JavacTreeMaker maker, boolean bool) { return maker.Return(maker.Literal(CTC_BOOLEAN, bool ? 1 : 0)); } } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 51642f86..4ef23170 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -22,6 +22,7 @@ package lombok.javac.handlers; import static lombok.javac.Javac.*; +import static lombok.javac.JavacTreeMaker.TypeTag.*; import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.Collection; @@ -37,6 +38,8 @@ import lombok.core.AnnotationValues; import lombok.core.TransformationsUtil; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; +import lombok.javac.JavacTreeMaker.TypeTag; import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import org.mangosdk.spi.ProviderFor; @@ -57,7 +60,6 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCSynchronized; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; @@ -213,7 +215,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source.get(), lazy, onMethod)); } - private JCMethodDecl createGetter(long access, JavacNode field, TreeMaker treeMaker, JCTree source, boolean lazy, List<JCAnnotation> onMethod) { + private JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker treeMaker, JCTree source, boolean lazy, List<JCAnnotation> onMethod) { JCVariableDecl fieldNode = (JCVariableDecl) field.get(); // Remember the type; lazy will change it @@ -268,7 +270,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { } if (!delegates.isEmpty()) { - ListBuffer<JCAnnotation> withoutDelegates = ListBuffer.lb(); + ListBuffer<JCAnnotation> withoutDelegates = new ListBuffer<JCAnnotation>(); for (JCAnnotation annotation : fieldNode.mods.annotations) { if (!delegates.contains(annotation)) { withoutDelegates.append(annotation); @@ -280,7 +282,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { return delegates; } - private List<JCStatement> createSimpleGetterBody(TreeMaker treeMaker, JavacNode field) { + private List<JCStatement> createSimpleGetterBody(JavacTreeMaker treeMaker, JavacNode field) { return List.<JCStatement>of(treeMaker.Return(createFieldAccessor(treeMaker, field, FieldAccess.ALWAYS_FIELD))); } @@ -288,9 +290,9 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { private static final String JLO = "java.lang.Object"; private static final List<JCExpression> NIL_EXPRESSION = List.nil(); - private static final java.util.Map<Integer, String> TYPE_MAP; + private static final java.util.Map<TypeTag, String> TYPE_MAP; static { - Map<Integer, String> m = new HashMap<Integer, String>(); + Map<TypeTag, String> m = new HashMap<TypeTag, String>(); m.put(CTC_INT, "java.lang.Integer"); m.put(CTC_DOUBLE, "java.lang.Double"); m.put(CTC_FLOAT, "java.lang.Float"); @@ -302,7 +304,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { TYPE_MAP = Collections.unmodifiableMap(m); } - private List<JCStatement> createLazyGetterBody(TreeMaker maker, JavacNode fieldNode, JCTree source) { + private List<JCStatement> createLazyGetterBody(JavacTreeMaker maker, JavacNode fieldNode, JCTree source) { /* java.lang.Object value = this.fieldName.get(); if (value == null) { @@ -326,7 +328,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { [END IF] */ - ListBuffer<JCStatement> statements = ListBuffer.lb(); + ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); JCVariableDecl field = (JCVariableDecl) fieldNode.get(); JCExpression copyOfRawFieldType = copyType(maker, field); @@ -334,7 +336,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { field.type = null; boolean isPrimitive = false; if (field.vartype instanceof JCPrimitiveTypeTree) { - String boxed = TYPE_MAP.get(((JCPrimitiveTypeTree)field.vartype).typetag); + String boxed = TYPE_MAP.get(typeTag(field.vartype)); if (boxed != null) { isPrimitive = true; field.vartype = chainDotsString(fieldNode, boxed); @@ -354,14 +356,14 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { /* if (value == null) { */ { JCSynchronized synchronizedStatement; /* synchronized (this.fieldName) { */ { - ListBuffer<JCStatement> synchronizedStatements = ListBuffer.lb(); + ListBuffer<JCStatement> synchronizedStatements = new ListBuffer<JCStatement>(); /* value = this.fieldName.get(); */ { JCExpressionStatement newAssign = maker.Exec(maker.Assign(maker.Ident(valueName), callGet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD)))); synchronizedStatements.append(newAssign); } /* if (value == null) { */ { - ListBuffer<JCStatement> innerIfStatements = ListBuffer.lb(); + ListBuffer<JCStatement> innerIfStatements = new ListBuffer<JCStatement>(); /* final RawValueType actualValue = INITIALIZER_EXPRESSION; */ { innerIfStatements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), actualValueName, copyOfRawFieldType, field.init)); } @@ -423,16 +425,16 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { } private JCMethodInvocation callGet(JavacNode source, JCExpression receiver) { - TreeMaker maker = source.getTreeMaker(); + JavacTreeMaker maker = source.getTreeMaker(); return maker.Apply(NIL_EXPRESSION, maker.Select(receiver, source.toName("get")), NIL_EXPRESSION); } private JCStatement callSet(JavacNode source, JCExpression receiver, JCExpression value) { - TreeMaker maker = source.getTreeMaker(); + JavacTreeMaker maker = source.getTreeMaker(); return maker.Exec(maker.Apply(NIL_EXPRESSION, maker.Select(receiver, source.toName("set")), List.<JCExpression>of(value))); } - private JCExpression copyType(TreeMaker treeMaker, JCVariableDecl fieldNode) { + private JCExpression copyType(JavacTreeMaker treeMaker, JCVariableDecl fieldNode) { return fieldNode.type != null ? treeMaker.Type(fieldNode.type) : fieldNode.vartype; } } diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 35a32be5..31478b66 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -28,12 +28,12 @@ import java.lang.annotation.Annotation; import lombok.core.AnnotationValues; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; 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.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; @@ -74,13 +74,13 @@ public class HandleLog { } private static JCFieldAccess selfType(JavacNode typeNode) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker 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, JCTree source) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); // private static final <loggerType> log = <factoryMethod>(<parameter>); JCExpression loggerType = chainDotsString(typeNode, framework.getLoggerTypeName()); @@ -164,7 +164,7 @@ public class HandleLog { // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); JUL(lombok.extern.java.Log.class, "java.util.logging.Logger", "java.util.logging.Logger.getLogger") { @Override public JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); JCExpression method = maker.Select(loggingType, typeNode.toName("getName")); return maker.Apply(List.<JCExpression>nil(), method, List.<JCExpression>nil()); } diff --git a/src/core/lombok/javac/handlers/NonNullHandler.java b/src/core/lombok/javac/handlers/HandleNonNull.java index 415d6032..21611a39 100644 --- a/src/core/lombok/javac/handlers/NonNullHandler.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.java @@ -36,18 +36,24 @@ import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCParens; import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCSynchronized; import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; import lombok.NonNull; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.core.AST.Kind; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import static lombok.javac.JavacTreeMaker.TypeTag.*; +import static lombok.javac.JavacTreeMaker.TreeTag.*; @ProviderFor(JavacAnnotationHandler.class) -public class NonNullHandler extends JavacAnnotationHandler<NonNull> { +@HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first. +public class HandleNonNull extends JavacAnnotationHandler<NonNull> { @Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) { if (annotationNode.up().getKind() == Kind.FIELD) { // This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc), @@ -74,7 +80,12 @@ public class NonNullHandler extends JavacAnnotationHandler<NonNull> { return; } - if (JavacHandlerUtil.isGenerated(declaration)) return; +// if (JavacHandlerUtil.isGenerated(declaration)) return; + + if (declaration.body == null) { + annotationNode.addWarning("@NonNull is meaningless on a parameter of an abstract method."); + return; + } // Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter, // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and @@ -91,17 +102,33 @@ public class NonNullHandler extends JavacAnnotationHandler<NonNull> { List<JCStatement> statements = declaration.body.stats; String expectedName = annotationNode.up().getName(); - for (JCStatement stat : statements) { - if (JavacHandlerUtil.isConstructorCall(stat)) continue; - String varNameOfNullCheck = returnVarNameIfNullCheck(stat); - if (varNameOfNullCheck == null) break; - if (varNameOfNullCheck.equals(expectedName)) return; + + /* Abort if the null check is already there, delving into try and synchronized statements */ { + List<JCStatement> stats = statements; + int idx = 0; + while (stats.size() > idx) { + JCStatement stat = stats.get(idx++); + if (JavacHandlerUtil.isConstructorCall(stat)) continue; + if (stat instanceof JCTry) { + stats = ((JCTry) stat).body.stats; + idx = 0; + continue; + } + if (stat instanceof JCSynchronized) { + stats = ((JCSynchronized) stat).body.stats; + idx = 0; + continue; + } + String varNameOfNullCheck = returnVarNameIfNullCheck(stat); + if (varNameOfNullCheck == null) break; + if (varNameOfNullCheck.equals(expectedName)) return; + } } List<JCStatement> tail = statements; List<JCStatement> head = List.nil(); for (JCStatement stat : statements) { - if (JavacHandlerUtil.isConstructorCall(stat) || JavacHandlerUtil.isGenerated(stat)) { + if (JavacHandlerUtil.isConstructorCall(stat) || (JavacHandlerUtil.isGenerated(stat) && isNullCheck(stat))) { tail = tail.tail; head = head.prepend(stat); continue; @@ -114,6 +141,10 @@ public class NonNullHandler extends JavacAnnotationHandler<NonNull> { declaration.body.stats = newList; } + private boolean isNullCheck(JCStatement stat) { + return returnVarNameIfNullCheck(stat) != null; + } + /** * Checks if the statement is of the form 'if (x == null) {throw WHATEVER;}, * where the block braces are optional. If it is of this form, returns "x". @@ -138,10 +169,10 @@ public class NonNullHandler extends JavacAnnotationHandler<NonNull> { while (cond instanceof JCParens) cond = ((JCParens) cond).expr; if (!(cond instanceof JCBinary)) return null; JCBinary bin = (JCBinary) cond; - if (getTag(bin) != CTC_EQUAL) return null; + if (!CTC_EQUAL.equals(treeTag(bin))) return null; if (!(bin.lhs instanceof JCIdent)) return null; if (!(bin.rhs instanceof JCLiteral)) return null; - if (((JCLiteral) bin.rhs).typetag != CTC_BOT) return null; + if (!CTC_BOT.equals(typeTag(bin.rhs))) return null; return ((JCIdent) bin.lhs).name.toString(); } } diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 282e6c2f..c4977b2b 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -26,23 +26,20 @@ import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.Collection; -import javax.lang.model.type.NoType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeVisitor; - import lombok.AccessLevel; import lombok.Setter; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.TransformationsUtil; +import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; 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.JCAssign; @@ -54,7 +51,6 @@ import com.sun.tools.javac.tree.JCTree.JCReturn; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; @@ -194,13 +190,13 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { injectMethod(fieldNode.up(), createdSetter); } - static JCMethodDecl createSetter(long access, JavacNode field, TreeMaker treeMaker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { String setterName = toSetterName(field); boolean returnThis = shouldReturnThis(field); return createSetter(access, field, treeMaker, setterName, returnThis, source, onMethod, onParam); } - static JCMethodDecl createSetter(long access, JavacNode field, TreeMaker treeMaker, String setterName, boolean shouldReturnThis, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, String setterName, boolean shouldReturnThis, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { if (setterName == null) return null; JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); @@ -208,14 +204,14 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { JCExpression fieldRef = createFieldAccessor(treeMaker, field, FieldAccess.ALWAYS_FIELD); JCAssign assign = treeMaker.Assign(fieldRef, treeMaker.Ident(fieldDecl.name)); - ListBuffer<JCStatement> statements = ListBuffer.lb(); + ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); List<JCAnnotation> nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN); List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN); Name methodName = field.toName(setterName); List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(nonNulls).appendList(nullables); - JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.FINAL, annsOnParam), fieldDecl.name, fieldDecl.vartype, null); + JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.FINAL | Flags.PARAMETER, annsOnParam), fieldDecl.name, fieldDecl.vartype, null); if (nonNulls.isEmpty()) { statements.append(treeMaker.Exec(assign)); @@ -232,7 +228,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { if (methodType == null) { //WARNING: Do not use field.getSymbolTable().voidType - that field has gone through non-backwards compatible API changes within javac1.6. - methodType = treeMaker.Type(new JCNoType(CTC_VOID)); + methodType = treeMaker.Type(Javac.createVoidType(treeMaker, CTC_VOID)); shouldReturnThis = false; } @@ -257,22 +253,4 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { copyJavadoc(field, decl, CopyJavadoc.SETTER); return decl; } - - private static class JCNoType extends Type implements NoType { - public JCNoType(int tag) { - super(tag, null); - } - - @Override - public TypeKind getKind() { - if (tag == CTC_VOID) return TypeKind.VOID; - if (tag == CTC_NONE) return TypeKind.NONE; - throw new AssertionError("Unexpected tag: " + tag); - } - - @Override - public <R, P> R accept(TypeVisitor<R, P> v, P p) { - return v.visitNoType(this, p); - } - } } diff --git a/src/core/lombok/javac/handlers/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java index c818f630..b41277c3 100644 --- a/src/core/lombok/javac/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/javac/handlers/HandleSneakyThrows.java @@ -29,14 +29,15 @@ import java.util.Collections; import lombok.SneakyThrows; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; 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.JCBlock; import com.sun.tools.javac.tree.JCTree.JCExpression; @@ -49,6 +50,7 @@ import com.sun.tools.javac.util.List; * Handles the {@code lombok.SneakyThrows} annotation for javac. */ @ProviderFor(JavacAnnotationHandler.class) +@HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { @Override public void handle(AnnotationValues<SneakyThrows> annotation, JCAnnotation ast, JavacNode annotationNode) { deleteAnnotationIfNeccessary(annotationNode, SneakyThrows.class); @@ -113,7 +115,7 @@ public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { } private JCStatement buildTryCatchBlock(JavacNode node, List<JCStatement> contents, String exception, JCTree source) { - TreeMaker maker = node.getTreeMaker(); + JavacTreeMaker maker = node.getTreeMaker(); JCBlock tryBlock = setGeneratedBy(maker.Block(0, contents), source); diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java index 2bca49e9..661a7c2a 100644 --- a/src/core/lombok/javac/handlers/HandleSynchronized.java +++ b/src/core/lombok/javac/handlers/HandleSynchronized.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2013 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,8 +26,10 @@ import static lombok.javac.handlers.JavacHandlerUtil.*; import lombok.Synchronized; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; import org.mangosdk.spi.ProviderFor; @@ -39,13 +41,13 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; /** * Handles the {@code lombok.Synchronized} annotation for javac. */ @ProviderFor(JavacAnnotationHandler.class) +@HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { private static final String INSTANCE_LOCK_NAME = "$lock"; private static final String STATIC_LOCK_NAME = "$LOCK"; @@ -77,7 +79,7 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; } - TreeMaker maker = methodNode.getTreeMaker().at(ast.pos); + JavacTreeMaker maker = methodNode.getTreeMaker().at(ast.pos); if (fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS) { if (!autoMake) { diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index 333393da..9bd5b920 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2013 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 @@ -31,12 +31,12 @@ import lombok.core.AnnotationValues; import lombok.core.AST.Kind; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; 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.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -129,7 +129,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { return; } - ListBuffer<JavacNode> nodesForToString = ListBuffer.lb(); + ListBuffer<JavacNode> nodesForToString = new ListBuffer<JavacNode>(); if (includes != null) { for (JavacNode child : typeNode.down()) { if (child.getKind() != Kind.FIELD) continue; @@ -167,7 +167,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { } static JCMethodDecl createToString(JavacNode typeNode, Collection<JavacNode> fields, boolean includeFieldNames, boolean callSuper, FieldAccess fieldAccess, JCTree source) { - TreeMaker maker = typeNode.getTreeMaker(); + JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(chainDots(typeNode, "java", "lang", "Override"), List.<JCExpression>nil()); JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java index b3f218b8..9cfa4531 100644 --- a/src/core/lombok/javac/handlers/HandleWither.java +++ b/src/core/lombok/javac/handlers/HandleWither.java @@ -33,6 +33,7 @@ import lombok.core.TransformationsUtil; import lombok.experimental.Wither; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.CopyJavadoc; import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; @@ -51,7 +52,6 @@ import com.sun.tools.javac.tree.JCTree.JCReturn; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; @@ -201,27 +201,25 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { injectMethod(fieldNode.up(), createdWither); } - private JCMethodDecl createWither(long access, JavacNode field, TreeMaker treeMaker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + private JCMethodDecl createWither(long access, JavacNode field, JavacTreeMaker maker, JCTree source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { String witherName = toWitherName(field); if (witherName == null) return null; JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); - ListBuffer<JCStatement> statements = ListBuffer.lb(); + ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); List<JCAnnotation> nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN); List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN); Name methodName = field.toName(witherName); List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(nonNulls).appendList(nullables); - JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.FINAL, annsOnParam), fieldDecl.name, fieldDecl.vartype, null); + JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER, annsOnParam), fieldDecl.name, fieldDecl.vartype, null); JCExpression selfType = cloneSelfType(field); if (selfType == null) return null; - TreeMaker maker = field.getTreeMaker(); - - ListBuffer<JCExpression> args = ListBuffer.lb(); + ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); for (JavacNode child : field.up().down()) { if (child.getKind() != Kind.FIELD) continue; JCVariableDecl childDecl = (JCVariableDecl) child.get(); @@ -247,14 +245,14 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { if (nonNulls.isEmpty()) { statements.append(returnStatement); } else { - JCStatement nullCheck = generateNullCheck(treeMaker, field); + JCStatement nullCheck = generateNullCheck(maker, field); if (nullCheck != null) statements.append(nullCheck); statements.append(returnStatement); } JCExpression returnType = cloneSelfType(field); - JCBlock methodBody = treeMaker.Block(0, statements.toList()); + JCBlock methodBody = maker.Block(0, statements.toList()); List<JCTypeParameter> methodGenericParams = List.nil(); List<JCVariableDecl> parameters = List.of(param); List<JCExpression> throwsClauses = List.nil(); @@ -263,9 +261,9 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod); if (isFieldDeprecated(field)) { - annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(chainDots(field, "java", "lang", "Deprecated"), List.<JCExpression>nil())); + annsOnMethod = annsOnMethod.prepend(maker.Annotation(chainDots(field, "java", "lang", "Deprecated"), List.<JCExpression>nil())); } - JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, returnType, + JCMethodDecl decl = recursiveSetGeneratedBy(maker.MethodDef(maker.Modifiers(access, annsOnMethod), methodName, returnType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source); copyJavadoc(field, decl, CopyJavadoc.WITHER); return decl; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index d7d29da2..50e80169 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -44,10 +44,14 @@ import lombok.core.AnnotationValues.AnnotationValue; import lombok.core.TransformationsUtil; import lombok.core.TypeResolver; import lombok.experimental.Accessors; +import lombok.javac.Javac; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.tree.DocCommentTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; @@ -72,7 +76,6 @@ import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.tree.JCTree.TypeBoundKind; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; @@ -96,6 +99,7 @@ public class JavacHandlerUtil { } @Override public void scan(JCTree tree) { + if (tree == null) return; setGeneratedBy(tree, source); super.scan(tree); } @@ -133,10 +137,12 @@ public class JavacHandlerUtil { } public static <T extends JCTree> T setGeneratedBy(T node, JCTree source) { + if (node == null) return null; synchronized (generatedNodes) { if (source == null) generatedNodes.remove(node); else generatedNodes.put(node, new WeakReference<JCTree>(source)); } + if (source != null) node.pos = source.pos; return node; } @@ -213,6 +219,17 @@ public class JavacHandlerUtil { } /** + * Returns if a node is marked deprecated (as picked up on by the parser). + * @param node the node to check (type, method, or field decl). + */ + public static boolean nodeHasDeprecatedFlag(JCTree node) { + if (node instanceof JCVariableDecl) return (((JCVariableDecl) node).mods.flags & Flags.DEPRECATED) != 0; + if (node instanceof JCMethodDecl) return (((JCMethodDecl) node).mods.flags & Flags.DEPRECATED) != 0; + if (node instanceof JCClassDecl) return (((JCClassDecl) node).mods.flags & Flags.DEPRECATED) != 0; + return false; + } + + /** * Creates an instance of {@code AnnotationValues} for the provided AST Node. * * @param type An annotation class type, such as {@code lombok.Getter.class}. @@ -334,7 +351,7 @@ public class JavacHandlerUtil { public static void deleteImportFromCompilationUnit(JavacNode node, String name) { if (inNetbeansEditor(node)) return; if (!node.shouldDeleteLombokAnnotations()) return; - ListBuffer<JCTree> newDefs = ListBuffer.lb(); + ListBuffer<JCTree> newDefs = new ListBuffer<JCTree>(); JCCompilationUnit unit = (JCCompilationUnit) node.top().get(); @@ -350,7 +367,7 @@ public class JavacHandlerUtil { } private static List<JCAnnotation> filterList(List<JCAnnotation> annotations, JCTree jcTree) { - ListBuffer<JCAnnotation> newAnnotations = ListBuffer.lb(); + ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<JCAnnotation>(); for (JCAnnotation ann : annotations) { if (jcTree != ann) newAnnotations.append(ann); } @@ -429,11 +446,11 @@ public class JavacHandlerUtil { public static JCExpression cloneSelfType(JavacNode field) { JavacNode typeNode = field; - TreeMaker maker = field.getTreeMaker(); + JavacTreeMaker maker = field.getTreeMaker(); while (typeNode != null && typeNode.getKind() != Kind.TYPE) typeNode = typeNode.up(); if (typeNode != null && typeNode.get() instanceof JCClassDecl) { JCClassDecl type = (JCClassDecl) typeNode.get(); - ListBuffer<JCExpression> typeArgs = ListBuffer.lb(); + ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); if (!type.typarams.isEmpty()) { for (JCTypeParameter tp : type.typarams) { typeArgs.append(maker.Ident(tp.name)); @@ -456,6 +473,37 @@ public class JavacHandlerUtil { return varType != null && varType.toString().equals("boolean"); } + public static Name removePrefixFromField(JavacNode field) { + String[] prefixes = null; + for (JavacNode node : field.down()) { + if (annotationTypeMatches(Accessors.class, node)) { + prefixes = createAnnotation(Accessors.class, node).getInstance().prefix(); + break; + } + } + + if (prefixes == null) { + JavacNode current = field.up(); + outer: + while (current != null) { + for (JavacNode node : current.down()) { + if (annotationTypeMatches(Accessors.class, node)) { + prefixes = createAnnotation(Accessors.class, node).getInstance().prefix(); + break outer; + } + } + current = current.up(); + } + } + + if (prefixes != null && prefixes.length > 0) { + CharSequence newName = TransformationsUtil.removePrefix(field.getName(), prefixes); + if (newName != null) return field.toName(newName.toString()); + } + + return ((JCVariableDecl) field.get()).name; + } + public static AnnotationValues<Accessors> getAccessorsForField(JavacNode field) { for (JavacNode node : field.down()) { if (annotationTypeMatches(Accessors.class, node)) { @@ -707,11 +755,11 @@ public class JavacHandlerUtil { /** * Creates an expression that reads the field. Will either be {@code this.field} or {@code this.getField()} depending on whether or not there's a getter. */ - static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, FieldAccess fieldAccess) { + static JCExpression createFieldAccessor(JavacTreeMaker maker, JavacNode field, FieldAccess fieldAccess) { return createFieldAccessor(maker, field, fieldAccess, null); } - static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, FieldAccess fieldAccess, JCExpression receiver) { + static JCExpression createFieldAccessor(JavacTreeMaker maker, JavacNode field, FieldAccess fieldAccess, JCExpression receiver) { boolean lookForGetter = lookForGetter(field, fieldAccess); GetterMethod getter = lookForGetter ? findGetter(field) : null; @@ -839,7 +887,7 @@ public class JavacHandlerUtil { } private static void addSuppressWarningsAll(JCModifiers mods, JavacNode node, int pos, JCTree source) { - TreeMaker maker = node.getTreeMaker(); + JavacTreeMaker maker = node.getTreeMaker(); JCExpression suppressWarningsType = chainDots(node, "java", "lang", "SuppressWarnings"); JCLiteral allLiteral = maker.Literal("all"); suppressWarningsType.pos = pos; @@ -850,7 +898,7 @@ public class JavacHandlerUtil { } private static List<JCTree> addAllButOne(List<JCTree> defs, int idx) { - ListBuffer<JCTree> out = ListBuffer.lb(); + ListBuffer<JCTree> out = new ListBuffer<JCTree>(); int i = 0; for (JCTree def : defs) { if (i++ != idx) out.append(def); @@ -890,7 +938,7 @@ public class JavacHandlerUtil { assert elems != null; assert elems.length > 0; - TreeMaker maker = node.getTreeMaker(); + JavacTreeMaker maker = node.getTreeMaker(); if (pos != -1) maker = maker.at(pos); JCExpression e = maker.Ident(node.toName(elems[0])); for (int i = 1 ; i < elems.length ; i++) { @@ -921,7 +969,7 @@ public class JavacHandlerUtil { * Only the simple name is checked - the package and any containing class are ignored. */ public static List<JCAnnotation> findAnnotations(JavacNode fieldNode, Pattern namePattern) { - ListBuffer<JCAnnotation> result = ListBuffer.lb(); + ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>(); for (JavacNode child : fieldNode.down()) { if (child.getKind() == Kind.ANNOTATION) { JCAnnotation annotation = (JCAnnotation) child.get(); @@ -940,15 +988,15 @@ public class JavacHandlerUtil { * Generates a new statement that checks if the given variable is null, and if so, throws a {@code NullPointerException} with the * variable name as message. */ - public static JCStatement generateNullCheck(TreeMaker treeMaker, JavacNode variable) { + public static JCStatement generateNullCheck(JavacTreeMaker maker, JavacNode variable) { JCVariableDecl varDecl = (JCVariableDecl) variable.get(); if (isPrimitive(varDecl.vartype)) return null; Name fieldName = varDecl.name; JCExpression npe = chainDots(variable, "java", "lang", "NullPointerException"); - JCTree exception = treeMaker.NewClass(null, List.<JCExpression>nil(), npe, List.<JCExpression>of(treeMaker.Literal(fieldName.toString())), null); - JCStatement throwStatement = treeMaker.Throw(exception); - JCBlock throwBlock = treeMaker.Block(0, List.of(throwStatement)); - return treeMaker.If(treeMaker.Binary(CTC_EQUAL, treeMaker.Ident(fieldName), treeMaker.Literal(CTC_BOT, null)), throwBlock, null); + JCExpression exception = maker.NewClass(null, List.<JCExpression>nil(), npe, List.<JCExpression>of(maker.Literal(fieldName.toString())), null); + JCStatement throwStatement = maker.Throw(exception); + JCBlock throwBlock = maker.Block(0, List.of(throwStatement)); + return maker.If(maker.Binary(CTC_EQUAL, maker.Ident(fieldName), maker.Literal(CTC_BOT, null)), throwBlock, null); } /** @@ -971,7 +1019,7 @@ public class JavacHandlerUtil { if (idx > -1) matched[idx] = true; } - ListBuffer<Integer> problematic = ListBuffer.lb(); + ListBuffer<Integer> problematic = new ListBuffer<Integer>(); for (int i = 0 ; i < list.size() ; i++) { if (!matched[i]) problematic.append(i); } @@ -980,8 +1028,8 @@ public class JavacHandlerUtil { } static List<JCAnnotation> unboxAndRemoveAnnotationParameter(JCAnnotation ast, String parameterName, String errorName, JavacNode errorNode) { - ListBuffer<JCExpression> params = ListBuffer.lb(); - ListBuffer<JCAnnotation> result = ListBuffer.lb(); + ListBuffer<JCExpression> params = new ListBuffer<JCExpression>(); + ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>(); errorNode.removeDeferredErrors(); @@ -1005,9 +1053,9 @@ public class JavacHandlerUtil { if (valueOfParam instanceof JCAnnotation) { String dummyAnnotationName = ((JCAnnotation) valueOfParam).annotationType.toString(); - dummyAnnotationName = dummyAnnotationName.replace("_", ""); + dummyAnnotationName = dummyAnnotationName.replace("_", "").replace("$", "").replace("x", "").replace("X", ""); if (dummyAnnotationName.length() > 0) { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); continue outer; } for (JCExpression expr : ((JCAnnotation) valueOfParam).args) { @@ -1016,7 +1064,7 @@ public class JavacHandlerUtil { if ("value".equals(id.name.toString())) { expr = ((JCAssign) expr).rhs; } else { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); continue outer; } } @@ -1028,12 +1076,12 @@ public class JavacHandlerUtil { if (expr2 instanceof JCAnnotation) { result.append((JCAnnotation) expr2); } else { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); continue outer; } } } else { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); continue outer; } } @@ -1041,7 +1089,7 @@ public class JavacHandlerUtil { if (valueOfParam instanceof JCNewArray && ((JCNewArray) valueOfParam).elems.isEmpty()) { // Then we just remove it and move on (it's onMethod={} for example). } else { - errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); } } } @@ -1049,15 +1097,15 @@ public class JavacHandlerUtil { return result.toList(); } - public static List<JCTypeParameter> copyTypeParams(TreeMaker maker, List<JCTypeParameter> params) { + public static List<JCTypeParameter> copyTypeParams(JavacTreeMaker maker, List<JCTypeParameter> params) { if (params == null || params.isEmpty()) return params; - ListBuffer<JCTypeParameter> out = ListBuffer.lb(); + ListBuffer<JCTypeParameter> out = new ListBuffer<JCTypeParameter>(); for (JCTypeParameter tp : params) out.append(maker.TypeParameter(tp.name, tp.bounds)); return out.toList(); } - public static JCExpression namePlusTypeParamsToTypeReference(TreeMaker maker, Name typeName, List<JCTypeParameter> params) { - ListBuffer<JCExpression> typeArgs = ListBuffer.lb(); + public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, Name typeName, List<JCTypeParameter> params) { + ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); if (!params.isEmpty()) { for (JCTypeParameter param : params) { @@ -1093,7 +1141,7 @@ public class JavacHandlerUtil { } static List<JCAnnotation> copyAnnotations(List<? extends JCExpression> in) { - ListBuffer<JCAnnotation> out = ListBuffer.lb(); + ListBuffer<JCAnnotation> out = new ListBuffer<JCAnnotation>(); for (JCExpression expr : in) { if (!(expr instanceof JCAnnotation)) continue; out.append((JCAnnotation) expr.clone()); @@ -1135,13 +1183,13 @@ public class JavacHandlerUtil { * the class's own parameter, but as its a static method, the static method's notion of {@code T} is different from the class notion of {@code T}. If you're duplicating * a type used in the class context, you need to use this method. */ - public static JCExpression cloneType(TreeMaker maker, JCExpression in, JCTree source) { + public static JCExpression cloneType(JavacTreeMaker maker, JCExpression in, JCTree source) { JCExpression out = cloneType0(maker, in); if (out != null) recursiveSetGeneratedBy(out, source); return out; } - private static JCExpression cloneType0(TreeMaker maker, JCTree in) { + private static JCExpression cloneType0(JavacTreeMaker maker, JCTree in) { if (in == null) return null; if (in instanceof JCPrimitiveTypeTree) return (JCExpression) in; @@ -1162,7 +1210,7 @@ public class JavacHandlerUtil { if (in instanceof JCTypeApply) { JCTypeApply ta = (JCTypeApply) in; - ListBuffer<JCExpression> lb = ListBuffer.lb(); + ListBuffer<JCExpression> lb = new ListBuffer<JCExpression>(); for (JCExpression typeArg : ta.arguments) { lb.append(cloneType0(maker, typeArg)); } @@ -1279,15 +1327,57 @@ public class JavacHandlerUtil { if (copyMode == null) copyMode = CopyJavadoc.VERBATIM; try { JCCompilationUnit cu = ((JCCompilationUnit) from.top().get()); - if (cu.docComments != null) { - String javadoc = cu.docComments.get(from.get()); - - if (javadoc != null) { - String[] filtered = copyMode.split(javadoc); - cu.docComments.put(to, filtered[0]); - cu.docComments.put(from.get(), filtered[1]); - } + Object dc = Javac.getDocComments(cu); + if (dc instanceof Map) { + copyJavadoc_jdk6_7(from, to, copyMode, dc); + } else if (Javac.instanceOfDocCommentTable(dc)) { + CopyJavadoc_8.copyJavadoc(from, to, copyMode, dc); } } catch (Exception ignore) {} } + + private static class CopyJavadoc_8 { + static void copyJavadoc(JavacNode from, JCTree to, CopyJavadoc copyMode, Object dc) { + DocCommentTable dct = (DocCommentTable) dc; + Comment javadoc = dct.getComment(from.get()); + + if (javadoc != null) { + String[] filtered = copyMode.split(javadoc.getText()); + dct.putComment(to, createJavadocComment(filtered[0], from)); + dct.putComment(from.get(), createJavadocComment(filtered[1], from)); + } + } + + private static Comment createJavadocComment(final String text, final JavacNode field) { + return new Comment() { + @Override public String getText() { + return text; + } + + @Override public int getSourcePos(int index) { + return -1; + } + + @Override public CommentStyle getStyle() { + return CommentStyle.JAVADOC; + } + + @Override public boolean isDeprecated() { + return text.contains("@deprecated") && field.getKind() == Kind.FIELD && isFieldDeprecated(field); + } + }; + } + } + + @SuppressWarnings({"unchecked", "all"}) + private static void copyJavadoc_jdk6_7(JavacNode from, JCTree to, CopyJavadoc copyMode, Object dc) { + Map<JCTree, String> docComments = (Map<JCTree, String>) dc; + String javadoc = docComments.get(from.get()); + + if (javadoc != null) { + String[] filtered = copyMode.split(javadoc); + docComments.put(to, filtered[0]); + docComments.put(from.get(), filtered[1]); + } + } } diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index f4e02786..0128e44f 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -52,7 +52,6 @@ import lombok.javac.LombokOptions; import com.sun.tools.javac.comp.Todo; import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.main.OptionName; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; import com.zwitserloot.cmdreader.CmdReader; @@ -359,12 +358,12 @@ public class Delombok { } public boolean delombok() throws IOException { - LombokOptions options = LombokOptions.replaceWithDelombokOptions(context); - options.put(OptionName.ENCODING, charset.name()); - if (classpath != null) options.put(OptionName.CLASSPATH, classpath); - if (sourcepath != null) options.put(OptionName.SOURCEPATH, sourcepath); - if (bootclasspath != null) options.put(OptionName.BOOTCLASSPATH, bootclasspath); - options.put("compilePolicy", "attr"); + LombokOptions options = LombokOptionsFactory.getDelombokOptions(context); + options.putJavacOption("ENCODING", charset.name()); + if (classpath != null) options.putJavacOption("CLASSPATH", classpath); + if (sourcepath != null) options.putJavacOption("SOURCEPATH", sourcepath); + if (bootclasspath != null) options.putJavacOption("BOOTCLASSPATH", bootclasspath); + options.put("compilePolicy", "check"); CommentCatcher catcher = CommentCatcher.create(context); JavaCompiler compiler = catcher.getCompiler(); @@ -375,10 +374,7 @@ public class Delombok { compiler.initProcessAnnotations(Collections.singleton(new lombok.javac.apt.Processor())); for (File fileToParse : filesToParse) { - - @SuppressWarnings("deprecation") - JCCompilationUnit unit = compiler.parse(fileToParse.getAbsolutePath()); - + @SuppressWarnings("deprecation") JCCompilationUnit unit = compiler.parse(fileToParse.getAbsolutePath()); baseMap.put(unit, fileToBase.get(fileToParse)); roots.add(unit); } @@ -387,8 +383,17 @@ public class Delombok { return false; } - JavaCompiler delegate = compiler.processAnnotations(compiler.enterTrees(toJavacList(roots))); - callFlowMethodOnJavaCompiler(delegate, callAttributeMethodOnJavaCompiler(delegate, delegate.todo)); + for (JCCompilationUnit unit : roots) { + catcher.setComments(unit, new DocCommentIntegrator().integrate(catcher.getComments(unit), unit)); + } + + com.sun.tools.javac.util.List<JCCompilationUnit> trees = compiler.enterTrees(toJavacList(roots)); + + JavaCompiler delegate = compiler.processAnnotations(trees); + + Object care = callAttributeMethodOnJavaCompiler(delegate, delegate.todo); + + callFlowMethodOnJavaCompiler(delegate, care); for (JCCompilationUnit unit : roots) { DelombokResult result = new DelombokResult(catcher.getComments(unit), unit, force || options.isChanged(unit)); if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged"); diff --git a/src/delombok/lombok/delombok/DelombokApp.java b/src/delombok/lombok/delombok/DelombokApp.java index e0d6ef1c..276bd7de 100644 --- a/src/delombok/lombok/delombok/DelombokApp.java +++ b/src/delombok/lombok/delombok/DelombokApp.java @@ -84,10 +84,9 @@ public class DelombokApp extends LombokApp { return null; } - @SuppressWarnings("resource") // The jar file is used for the lifetime of the classLoader, therefore the lifetime of delombok. // Since we only read from it, not closing it should not be a problem. - final JarFile toolsJarFile = new JarFile(toolsJar); + @SuppressWarnings({"resource", "all"}) final JarFile toolsJarFile = new JarFile(toolsJar); ClassLoader loader = new ClassLoader() { private Class<?> loadStreamAsClass(String name, boolean resolve, InputStream in) throws ClassNotFoundException { diff --git a/src/delombok/lombok/delombok/DocCommentIntegrator.java b/src/delombok/lombok/delombok/DocCommentIntegrator.java new file mode 100644 index 00000000..0955a003 --- /dev/null +++ b/src/delombok/lombok/delombok/DocCommentIntegrator.java @@ -0,0 +1,127 @@ +package lombok.delombok; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import lombok.javac.CommentInfo; +import lombok.javac.Javac; +import lombok.javac.handlers.JavacHandlerUtil; + +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.tree.DocCommentTable; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; + +public class DocCommentIntegrator { + /** + * Returns the same comment list as when this integrator was created, minus all doc comments that have been successfully integrated into the compilation unit. + */ + public List<CommentInfo> integrate(List<CommentInfo> comments, JCCompilationUnit unit) { + List<CommentInfo> out = new ArrayList<CommentInfo>(); + CommentInfo lastExcisedComment = null; + JCTree lastNode = null; + + for (CommentInfo cmt : comments) { + if (!cmt.isJavadoc()) { + out.add(cmt); + continue; + } + + JCTree node = findJavadocableNodeOnOrAfter(unit, cmt.endPos); + if (node == null) { + out.add(cmt); + continue; + } + + if (node == lastNode) { + out.add(lastExcisedComment); + } + if (!attach(unit, node, cmt)) { + out.add(cmt); + } else { + lastNode = node; + lastExcisedComment = cmt; + } + } + return out; + } + + private static final Pattern CONTENT_STRIPPER = Pattern.compile("^(?:\\s*\\*)?[ \\t]*(.*?)$", Pattern.MULTILINE); + @SuppressWarnings("unchecked") private boolean attach(JCCompilationUnit top, final JCTree node, CommentInfo cmt) { + String docCommentContent = cmt.content; + if (docCommentContent.startsWith("/**")) docCommentContent = docCommentContent.substring(3); + if (docCommentContent.endsWith("*/")) docCommentContent = docCommentContent.substring(0, docCommentContent.length() -2); + docCommentContent = CONTENT_STRIPPER.matcher(docCommentContent).replaceAll("$1"); + docCommentContent = docCommentContent.trim(); + + if (Javac.getDocComments(top) == null) Javac.initDocComments(top); + + Object map_ = Javac.getDocComments(top); + if (map_ instanceof Map) { + ((Map<JCTree, String>) map_).put(node, docCommentContent); + return true; + } else if (Javac.instanceOfDocCommentTable(map_)) { + CommentAttacher_8.attach(node, docCommentContent, map_); + return true; + } + + return false; + } + + /* Container for code which will cause class loader exceptions on javac below 8. By being in a separate class, we avoid the problem. */ + private static class CommentAttacher_8 { + static void attach(final JCTree node, String docCommentContent, Object map_) { + final String docCommentContent_ = docCommentContent; + ((DocCommentTable) map_).putComment(node, new Comment() { + @Override public String getText() { + return docCommentContent_; + } + + @Override public int getSourcePos(int index) { + return -1; + } + + @Override public CommentStyle getStyle() { + return CommentStyle.JAVADOC; + } + + @Override public boolean isDeprecated() { + return JavacHandlerUtil.nodeHasDeprecatedFlag(node); + } + }); + } + } + + private JCTree findJavadocableNodeOnOrAfter(JCCompilationUnit unit, int endPos) { + if (unit.pid != null && endPos <= unit.pid.pos) return null; + Iterator<JCTree> it = unit.defs.iterator(); + + while (it.hasNext()) { + JCTree node = it.next(); + if (node.pos < endPos) { + if (node instanceof JCClassDecl) { + com.sun.tools.javac.util.List<JCTree> defs = ((JCClassDecl) node).defs; + if (!defs.isEmpty()) while (!defs.tail.isEmpty()) defs = defs.tail; + if (defs.head != null && defs.head.pos >= endPos) { + // The associated node is IN this class declaration, so, replace the iterator. + // There's no point looking beyond this member in the current iteration 'context' + // so we don't need to save the old ref. Just start over inside this type declaration. + it = ((JCClassDecl) node).defs.iterator(); + } + } + continue; + } + + if (node instanceof JCMethodDecl || node instanceof JCClassDecl || node instanceof JCVariableDecl) return node; + return null; + } + + return null; + } +} diff --git a/src/delombok/lombok/delombok/LombokOptionsFactory.java b/src/delombok/lombok/delombok/LombokOptionsFactory.java new file mode 100644 index 00000000..e581593f --- /dev/null +++ b/src/delombok/lombok/delombok/LombokOptionsFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 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 + * 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.delombok; + +import lombok.javac.Javac; +import lombok.javac.Javac6BasedLombokOptions; +import lombok.javac.Javac8BasedLombokOptions; +import lombok.javac.LombokOptions; + +import com.sun.tools.javac.util.Context; + +public class LombokOptionsFactory { + enum LombokOptionCompilerVersion { + JDK7_AND_LOWER { + @Override LombokOptions createAndRegisterOptions(Context context) { + return Javac6BasedLombokOptions.replaceWithDelombokOptions(context); + } + }, + + JDK8 { + @Override LombokOptions createAndRegisterOptions(Context context) { + return Javac8BasedLombokOptions.replaceWithDelombokOptions(context); + } + }; + + abstract LombokOptions createAndRegisterOptions(Context context); + } + + public static LombokOptions getDelombokOptions(Context context) { + LombokOptions options; + if (Javac.getJavaCompilerVersion() < 8) { + options = LombokOptionCompilerVersion.JDK7_AND_LOWER.createAndRegisterOptions(context); + } else { + options = LombokOptionCompilerVersion.JDK8.createAndRegisterOptions(context); + } + return options; + } +} diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 1bb2ce23..f9152e68 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -29,34 +29,27 @@ */ package lombok.delombok; -import static com.sun.tools.javac.code.Flags.ANNOTATION; -import static com.sun.tools.javac.code.Flags.ENUM; -import static com.sun.tools.javac.code.Flags.INTERFACE; -import static com.sun.tools.javac.code.Flags.SYNTHETIC; -import static com.sun.tools.javac.code.Flags.StandardFlags; -import static com.sun.tools.javac.code.Flags.VARARGS; +import static com.sun.tools.javac.code.Flags.*; +import static lombok.javac.Javac.*; +import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; +import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import lombok.javac.CommentInfo; -import lombok.javac.Javac; import lombok.javac.CommentInfo.EndConnection; import lombok.javac.CommentInfo.StartConnection; +import lombok.javac.JavacTreeMaker.TreeTag; +import lombok.javac.JavacTreeMaker.TypeTag; import com.sun.source.tree.Tree; -import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.TypeTags; import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.TreeInfo; -import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayAccess; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; @@ -108,10 +101,14 @@ import com.sun.tools.javac.tree.JCTree.JCWhileLoop; import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.tree.JCTree.LetExpr; import com.sun.tools.javac.tree.JCTree.TypeBoundKind; +import com.sun.tools.javac.tree.DocCommentTable; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Convert; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Position; +//import com.sun.tools.javac.code.TypeTags; /** Prints out a tree as an indented Java source program. * @@ -122,214 +119,177 @@ import com.sun.tools.javac.util.Position; */ @SuppressWarnings("all") // Mainly sun code that has other warning settings public class PrettyCommentsPrinter extends JCTree.Visitor { - - private static final Method GET_TAG_METHOD; - private static final Field TAG_FIELD; + private static final TreeTag PARENS = treeTag("PARENS"); + private static final TreeTag IMPORT = treeTag("IMPORT"); + private static final TreeTag VARDEF = treeTag("VARDEF"); + private static final TreeTag SELECT = treeTag("SELECT"); - private static final int PARENS = Javac.getCtcInt(JCTree.class, "PARENS"); - private static final int IMPORT = Javac.getCtcInt(JCTree.class, "IMPORT"); - private static final int VARDEF = Javac.getCtcInt(JCTree.class, "VARDEF"); - private static final int SELECT = Javac.getCtcInt(JCTree.class, "SELECT"); - - private static final Map<Integer, String> OPERATORS; + private static final Map<TreeTag, String> OPERATORS; static { - Method m = null; - Field f = null; - try { - m = JCTree.class.getDeclaredMethod("getTag"); - } - catch (NoSuchMethodException e) { - try { - f = JCTree.class.getDeclaredField("tag"); - } - catch (NoSuchFieldException e1) { - e1.printStackTrace(); - } - } - GET_TAG_METHOD = m; - TAG_FIELD = f; - - Map<Integer, String> map = new HashMap<Integer, String>(); - - map.put(Javac.getCtcInt(JCTree.class, "POS"), "+"); - map.put(Javac.getCtcInt(JCTree.class, "NEG"), "-"); - map.put(Javac.getCtcInt(JCTree.class, "NOT"), "!"); - map.put(Javac.getCtcInt(JCTree.class, "COMPL"), "~"); - map.put(Javac.getCtcInt(JCTree.class, "PREINC"), "++"); - map.put(Javac.getCtcInt(JCTree.class, "PREDEC"), "--"); - map.put(Javac.getCtcInt(JCTree.class, "POSTINC"), "++"); - map.put(Javac.getCtcInt(JCTree.class, "POSTDEC"), "--"); - map.put(Javac.getCtcInt(JCTree.class, "NULLCHK"), "<*nullchk*>"); - map.put(Javac.getCtcInt(JCTree.class, "OR"), "||"); - map.put(Javac.getCtcInt(JCTree.class, "AND"), "&&"); - map.put(Javac.getCtcInt(JCTree.class, "EQ"), "=="); - map.put(Javac.getCtcInt(JCTree.class, "NE"), "!="); - map.put(Javac.getCtcInt(JCTree.class, "LT"), "<"); - map.put(Javac.getCtcInt(JCTree.class, "GT"), ">"); - map.put(Javac.getCtcInt(JCTree.class, "LE"), "<="); - map.put(Javac.getCtcInt(JCTree.class, "GE"), ">="); - map.put(Javac.getCtcInt(JCTree.class, "BITOR"), "|"); - map.put(Javac.getCtcInt(JCTree.class, "BITXOR"), "^"); - map.put(Javac.getCtcInt(JCTree.class, "BITAND"), "&"); - map.put(Javac.getCtcInt(JCTree.class, "SL"), "<<"); - map.put(Javac.getCtcInt(JCTree.class, "SR"), ">>"); - map.put(Javac.getCtcInt(JCTree.class, "USR"), ">>>"); - map.put(Javac.getCtcInt(JCTree.class, "PLUS"), "+"); - map.put(Javac.getCtcInt(JCTree.class, "MINUS"), "-"); - map.put(Javac.getCtcInt(JCTree.class, "MUL"), "*"); - map.put(Javac.getCtcInt(JCTree.class, "DIV"), "/"); - map.put(Javac.getCtcInt(JCTree.class, "MOD"), "%"); - - OPERATORS = map; + Map<TreeTag, String> map = new HashMap<TreeTag, String>(); + + map.put(treeTag("POS"), "+"); + map.put(treeTag("NEG"), "-"); + map.put(treeTag("NOT"), "!"); + map.put(treeTag("COMPL"), "~"); + map.put(treeTag("PREINC"), "++"); + map.put(treeTag("PREDEC"), "--"); + map.put(treeTag("POSTINC"), "++"); + map.put(treeTag("POSTDEC"), "--"); + map.put(treeTag("NULLCHK"), "<*nullchk*>"); + map.put(treeTag("OR"), "||"); + map.put(treeTag("AND"), "&&"); + map.put(treeTag("EQ"), "=="); + map.put(treeTag("NE"), "!="); + map.put(treeTag("LT"), "<"); + map.put(treeTag("GT"), ">"); + map.put(treeTag("LE"), "<="); + map.put(treeTag("GE"), ">="); + map.put(treeTag("BITOR"), "|"); + map.put(treeTag("BITXOR"), "^"); + map.put(treeTag("BITAND"), "&"); + map.put(treeTag("SL"), "<<"); + map.put(treeTag("SR"), ">>"); + map.put(treeTag("USR"), ">>>"); + map.put(treeTag("PLUS"), "+"); + map.put(treeTag("MINUS"), "-"); + map.put(treeTag("MUL"), "*"); + map.put(treeTag("DIV"), "/"); + map.put(treeTag("MOD"), "%"); + + map.put(treeTag("BITOR_ASG"), "|="); + map.put(treeTag("BITXOR_ASG"), "^="); + map.put(treeTag("BITAND_ASG"), "&="); + map.put(treeTag("SL_ASG"), "<<="); + map.put(treeTag("SR_ASG"), ">>="); + map.put(treeTag("USR_ASG"), ">>>="); + map.put(treeTag("PLUS_ASG"), "+="); + map.put(treeTag("MINUS_ASG"), "-="); + map.put(treeTag("MUL_ASG"), "*="); + map.put(treeTag("DIV_ASG"), "/="); + map.put(treeTag("MOD_ASG"), "%="); + + OPERATORS = map; } - static int getTag(JCTree tree) { - if (GET_TAG_METHOD != null) { - try { - return (Integer)GET_TAG_METHOD.invoke(tree); - } - catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - catch (InvocationTargetException e) { - throw new RuntimeException(e.getCause()); - } - } - try { - return TAG_FIELD.getInt(tree); - } - catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - private List<CommentInfo> comments; - private final JCCompilationUnit cu; - private boolean onNewLine = true; - private boolean aligned = false; - private boolean inParams = false; - - private boolean needsSpace = false; - private boolean needsNewLine = false; - private boolean needsAlign = false; - + private List<CommentInfo> comments; + private final JCCompilationUnit cu; + private boolean onNewLine = true; + private boolean aligned = false; + private boolean inParams = false; + + private boolean needsSpace = false; + private boolean needsNewLine = false; + private boolean needsAlign = false; + public PrettyCommentsPrinter(Writer out, JCCompilationUnit cu, List<CommentInfo> comments) { this.out = out; - this.comments = comments; - this.cu = cu; + this.comments = comments; + this.cu = cu; } - - private int endPos(JCTree tree) { - return tree.getEndPosition(cu.endPositions); - } - private void consumeComments(int until) throws IOException { - consumeComments(until, null); - } - private void consumeComments(int until, JCTree tree) throws IOException { - boolean prevNewLine = onNewLine; - boolean found = false; - CommentInfo head = comments.head; - while (comments.nonEmpty() && head.pos < until) { - if (tree != null && docComments != null && docComments.containsKey(tree) && head.isJavadoc() && noFurtherJavadocForthcoming(until)) { - // This is (presumably) the exact same javadoc that has already been associated with the node that we're just about to - // print. These javadoc can be modified by lombok handlers, and as such we should NOT print them from the consumed comments db, - // and instead print the actual javadoc associated with the upcoming node (which the visit method for that node will take care of). - } else { - printComment(head); - } - comments = comments.tail; - head = comments.head; - } - if (!onNewLine && prevNewLine) { - println(); - } - } + private int endPos(JCTree tree) { + return getEndPosition(tree, cu); + } - private boolean noFurtherJavadocForthcoming(int until) { - List<CommentInfo> c = comments; - if (c.nonEmpty()) c = c.tail; - while (c.nonEmpty()) { - if (c.head.pos >= until) return true; - if (c.head.isJavadoc()) return false; - c = c.tail; - } - return true; + private void consumeComments(int until) throws IOException { + consumeComments(until, null); } - + + private void consumeComments(int until, JCTree tree) throws IOException { + boolean prevNewLine = onNewLine; + boolean found = false; + CommentInfo head = comments.head; + while (comments.nonEmpty() && head.pos < until) { + printComment(head); + comments = comments.tail; + head = comments.head; + } + if (!onNewLine && prevNewLine) { + println(); + } + } + private void consumeTrailingComments(int from) throws IOException { - boolean prevNewLine = onNewLine; - CommentInfo head = comments.head; - boolean stop = false; - while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) { - from = head.endPos; - printComment(head); - stop = (head.end == EndConnection.ON_NEXT_LINE); - comments = comments.tail; - head = comments.head; - } - if (!onNewLine && prevNewLine) { - println(); - } - } - - private void printComment(CommentInfo comment) throws IOException { - prepareComment(comment.start); - print(comment.content); - switch (comment.end) { - case ON_NEXT_LINE: - if (!aligned) { - needsNewLine = true; - needsAlign = true; - } - break; - case AFTER_COMMENT: - needsSpace = true; - break; - case DIRECT_AFTER_COMMENT: - // do nothing - break; - } + boolean prevNewLine = onNewLine; + CommentInfo head = comments.head; + boolean stop = false; + while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) { + from = head.endPos; + printComment(head); + stop = (head.end == EndConnection.ON_NEXT_LINE); + comments = comments.tail; + head = comments.head; + } + if (!onNewLine && prevNewLine) { + println(); + } + } + + private void printComment(CommentInfo comment) throws IOException { + prepareComment(comment.start); + print(comment.content); + switch (comment.end) { + case ON_NEXT_LINE: + if (!aligned) { + needsNewLine = true; + needsAlign = true; + } + break; + case AFTER_COMMENT: + needsSpace = true; + break; + case DIRECT_AFTER_COMMENT: + // do nothing + break; + } + } + + private void prepareComment(StartConnection start) throws IOException { + switch (start) { + case DIRECT_AFTER_PREVIOUS: + needsSpace = false; + break; + case AFTER_PREVIOUS: + needsSpace = true; + break; + case START_OF_LINE: + needsNewLine = true; + needsAlign = false; + break; + case ON_NEXT_LINE: + if (!aligned) { + needsNewLine = true; + needsAlign = true; + } + break; + } } - - private void prepareComment(StartConnection start) throws IOException { - switch (start) { - case DIRECT_AFTER_PREVIOUS: - needsSpace = false; - break; - case AFTER_PREVIOUS: - needsSpace = true; - break; - case START_OF_LINE: - needsNewLine = true; - needsAlign = false; - break; - case ON_NEXT_LINE: - if (!aligned) { - needsNewLine = true; - needsAlign = true; - } - break; - } - } /** The output stream on which trees are printed. */ Writer out; - + /** The current left margin. */ int lmargin = 0; - + /** The enclosing class name. */ Name enclClassName; - + /** A hashtable mapping trees to their documentation comments * (can be null) */ Map<JCTree, String> docComments = null; + DocCommentTable docTable = null; + + String getJavadocFor(JCTree node) { + if (docComments != null) return docComments.get(node); + if (docTable != null) return docTable.getCommentText(node); + return null; + } /** Align code to be indented to left margin. */ @@ -339,19 +299,19 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { needsAlign = false; for (int i = 0; i < lmargin; i++) out.write("\t"); } - + /** Increase left margin by indentation width. */ void indent() { lmargin++; } - + /** Decrease left margin by indentation width. */ void undent() { lmargin--; } - + /** Enter a new precedence level. Emit a `(' if new precedence level * is less than precedence level so far. * @param contextPrec The precedence level in force so far. @@ -360,7 +320,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { void open(int contextPrec, int ownPrec) throws IOException { if (ownPrec < contextPrec) out.write("("); } - + /** Leave precedence level. Emit a `(' if inner precedence level * is less than precedence level we revert to. * @param contextPrec The precedence level we revert to. @@ -369,7 +329,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { void close(int contextPrec, int ownPrec) throws IOException { if (ownPrec < contextPrec) out.write(")"); } - + /** Print string, replacing all non-ascii character with unicode escapes. */ public void print(Object s) throws IOException { @@ -524,31 +484,28 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { * @param tree The tree for which a documentation comment should be printed. */ public void printDocComment(JCTree tree) throws IOException { - if (docComments != null) { - String dc = docComments.get(tree); - if (dc != null) { - print("/**"); println(); - int pos = 0; - int endpos = lineEndPos(dc, pos); - boolean atStart = true; - while (pos < dc.length()) { - String line = dc.substring(pos, endpos); - if (line.trim().isEmpty() && atStart) { - atStart = false; - continue; - } - atStart = false; - align(); - print(" *"); - if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); - print(dc.substring(pos, endpos)); println(); - pos = endpos + 1; - endpos = lineEndPos(dc, pos); - } - align(); print(" */"); println(); - align(); + String dc = getJavadocFor(tree); + if (dc == null) return; + print("/**"); println(); + int pos = 0; + int endpos = lineEndPos(dc, pos); + boolean atStart = true; + while (pos < dc.length()) { + String line = dc.substring(pos, endpos); + if (line.trim().isEmpty() && atStart) { + atStart = false; + continue; } + atStart = false; + align(); + print(" *"); + if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); + print(dc.substring(pos, endpos)); println(); + pos = endpos + 1; + endpos = lineEndPos(dc, pos); } + align(); print(" */"); println(); + align(); } //where static int lineEndPos(String s, int start) { @@ -633,7 +590,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { /** Is the given tree an enumerator definition? */ boolean isEnumerator(JCTree t) { - return getTag(t) == VARDEF && (((JCVariableDecl) t).mods.flags & ENUM) != 0; + return VARDEF.equals(treeTag(t)) && (((JCVariableDecl) t).mods.flags & ENUM) != 0; } /** Print unit consisting of package clause and import statements in toplevel, @@ -644,7 +601,9 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { * toplevel tree. */ public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException { - docComments = tree.docComments; + Object dc = getDocComments(tree); + if (dc instanceof Map) this.docComments = (Map) dc; + else if (dc instanceof DocCommentTable) this.docTable = (DocCommentTable) dc; printDocComment(tree); if (tree.pid != null) { consumeComments(tree.pos, tree); @@ -655,9 +614,9 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } boolean firstImport = true; for (List<JCTree> l = tree.defs; - l.nonEmpty() && (cdef == null || getTag(l.head) == IMPORT); + l.nonEmpty() && (cdef == null || IMPORT.equals(treeTag(l.head))); l = l.tail) { - if (getTag(l.head) == IMPORT) { + if (IMPORT.equals(treeTag(l.head))) { JCImport imp = (JCImport)l.head; Name name = TreeInfo.name(imp.qualid); if (name == name.table.fromChars(new char[] {'*'}, 0, 1) || @@ -741,9 +700,9 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { else print("class " + tree.name); printTypeParameters(tree.typarams); - if (tree.getExtendsClause() != null) { + if (getExtendsClause(tree) != null) { print(" extends "); - printExpr(tree.getExtendsClause()); + printExpr(getExtendsClause(tree)); } if (tree.implementing.nonEmpty()) { print(" implements "); @@ -826,7 +785,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitVarDef(JCVariableDecl tree) { try { - if (docComments != null && docComments.get(tree) != null) { + if (getJavadocFor(tree) != null) { println(); align(); } printDocComment(tree); @@ -876,7 +835,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { printStat(tree.body); align(); print(" while "); - if (getTag(tree.cond) == PARENS) { + if (PARENS.equals(treeTag(tree.cond))) { printExpr(tree.cond); } else { print("("); @@ -892,7 +851,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitWhileLoop(JCWhileLoop tree) { try { print("while "); - if (getTag(tree.cond) == PARENS) { + if (PARENS.equals(treeTag(tree.cond))) { printExpr(tree.cond); } else { print("("); @@ -910,7 +869,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { try { print("for ("); if (tree.init.nonEmpty()) { - if (getTag(tree.init.head) == VARDEF) { + if (VARDEF.equals(treeTag(tree.init.head))) { printExpr(tree.init.head); for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) { JCVariableDecl vdef = (JCVariableDecl)l.head; @@ -957,7 +916,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitSwitch(JCSwitch tree) { try { print("switch "); - if (getTag(tree.selector) == PARENS) { + if (PARENS.equals(treeTag(tree.selector))) { printExpr(tree.selector); } else { print("("); @@ -996,7 +955,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitSynchronized(JCSynchronized tree) { try { print("synchronized "); - if (getTag(tree.lock) == PARENS) { + if (PARENS.equals(treeTag(tree.lock))) { printExpr(tree.lock); } else { print("("); @@ -1077,7 +1036,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitIf(JCIf tree) { try { print("if "); - if (getTag(tree.cond) == PARENS) { + if (PARENS.equals(treeTag(tree.cond))) { printExpr(tree.cond); } else { print("("); @@ -1173,7 +1132,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitApply(JCMethodInvocation tree) { try { if (!tree.typeargs.isEmpty()) { - if (getTag(tree.meth) == SELECT) { + if (SELECT.equals(treeTag(tree.meth))) { JCFieldAccess left = (JCFieldAccess)tree.meth; printExpr(left.selected); print(".<"); @@ -1277,7 +1236,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } - public String operatorName(int tag) { + public String operatorName(TreeTag tag) { String result = OPERATORS.get(tag); if (result == null) throw new Error(); return result; @@ -1287,7 +1246,8 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { try { open(prec, TreeInfo.assignopPrec); printExpr(tree.lhs, TreeInfo.assignopPrec + 1); - print(" " + operatorName(getTag(tree) - JCTree.ASGOffset) + "= "); + String opname = operatorName(treeTag(tree)); + print(" " + opname + " "); printExpr(tree.rhs, TreeInfo.assignopPrec); close(prec, TreeInfo.assignopPrec); } catch (IOException e) { @@ -1297,10 +1257,10 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitUnary(JCUnary tree) { try { - int ownprec = TreeInfo.opPrec(getTag(tree)); - String opname = operatorName(getTag(tree)); + int ownprec = isOwnPrec(tree); + String opname = operatorName(treeTag(tree)); open(prec, ownprec); - if (getTag(tree) <= Javac.getCtcInt(JCTree.class, "PREDEC")) { + if (isPrefixUnary(tree)) { print(opname); printExpr(tree.arg, ownprec); } else { @@ -1312,11 +1272,19 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { throw new UncheckedIOException(e); } } - + + private int isOwnPrec(JCExpression tree) { + return treeTag(tree).getOperatorPrecedenceLevel(); + } + + private boolean isPrefixUnary(JCUnary tree) { + return treeTag(tree).isPrefixUnaryOp(); + } + public void visitBinary(JCBinary tree) { try { - int ownprec = TreeInfo.opPrec(getTag(tree)); - String opname = operatorName(getTag(tree)); + int ownprec = isOwnPrec(tree); + String opname = operatorName(treeTag(tree)); open(prec, ownprec); printExpr(tree.lhs, ownprec); print(" " + opname + " "); @@ -1381,78 +1349,39 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } public void visitLiteral(JCLiteral tree) { + TypeTag typeTag = typeTag(tree); try { - switch (tree.typetag) { - case TypeTags.INT: - print(tree.value.toString()); - break; - case TypeTags.LONG: - print(tree.value + "L"); - break; - case TypeTags.FLOAT: - print(tree.value + "F"); - break; - case TypeTags.DOUBLE: - print(tree.value.toString()); - break; - case TypeTags.CHAR: - print("\'" + - Convert.quote( - String.valueOf((char)((Number)tree.value).intValue())) + - "\'"); - break; - case TypeTags.BOOLEAN: - print(((Number)tree.value).intValue() == 1 ? "true" : "false"); - break; - case TypeTags.BOT: - print("null"); - break; - default: - print("\"" + Convert.quote(tree.value.toString()) + "\""); - break; + if (CTC_INT.equals(typeTag)) print(tree.value.toString()); + else if (CTC_LONG.equals(typeTag)) print(tree.value + "L"); + else if (CTC_FLOAT.equals(typeTag)) print(tree.value + "F"); + else if (CTC_DOUBLE.equals(typeTag)) print(tree.value.toString()); + else if (CTC_CHAR.equals(typeTag)) { + print("\'" + Convert.quote(String.valueOf((char)((Number)tree.value).intValue())) + "\'"); } + else if (CTC_BOOLEAN.equals(typeTag)) print(((Number)tree.value).intValue() == 1 ? "true" : "false"); + else if (CTC_BOT.equals(typeTag)) print("null"); + else print("\"" + Convert.quote(tree.value.toString()) + "\""); } catch (IOException e) { throw new UncheckedIOException(e); } } - public void visitTypeIdent(JCPrimitiveTypeTree tree) { - try { - switch(tree.typetag) { - case TypeTags.BYTE: - print("byte"); - break; - case TypeTags.CHAR: - print("char"); - break; - case TypeTags.SHORT: - print("short"); - break; - case TypeTags.INT: - print("int"); - break; - case TypeTags.LONG: - print("long"); - break; - case TypeTags.FLOAT: - print("float"); - break; - case TypeTags.DOUBLE: - print("double"); - break; - case TypeTags.BOOLEAN: - print("boolean"); - break; - case TypeTags.VOID: - print("void"); - break; - default: - print("error"); - break; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } + public void visitTypeIdent(JCPrimitiveTypeTree tree) { + TypeTag typetag = typeTag(tree); + try { + if (CTC_BYTE.equals(typetag)) print ("byte"); + else if (CTC_CHAR.equals(typetag)) print ("char"); + else if (CTC_SHORT.equals(typetag)) print ("short"); + else if (CTC_INT.equals(typetag)) print ("int"); + else if (CTC_LONG.equals(typetag)) print ("long"); + else if (CTC_FLOAT.equals(typetag)) print ("float"); + else if (CTC_DOUBLE.equals(typetag)) print ("double"); + else if (CTC_BOOLEAN.equals(typetag)) print ("boolean"); + else if (CTC_VOID.equals(typetag)) print ("void"); + else print("error"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } public void visitTypeArray(JCArrayTypeTree tree) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 8c6011bc..ccee5575 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -275,7 +275,6 @@ public class EclipsePatcher extends Agent { .methodToWrap(new Hook("org.eclipse.jdt.internal.compiler.ClassFile", "getBytes", "byte[]")) .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "runPostCompiler", "byte[]", "byte[]", "java.lang.String")) .requestExtra(StackRequest.PARAM3) - .transplant() .build()); } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java index 0002e26e..d4b8c763 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java @@ -329,7 +329,7 @@ public class PatchFixes { return newSimpleNames; } - public static byte[] runPostCompiler(byte[] bytes, String fileName) { + public static byte[] runPostCompiler(byte[] bytes, String fileName) { byte[] transformed = PostCompiler.applyTransformations(bytes, fileName, DiagnosticsReceiver.CONSOLE); return transformed == null ? bytes : transformed; } diff --git a/src/stubs/com/sun/tools/javac/main/Option.java b/src/stubs/com/sun/tools/javac/main/Option.java new file mode 100644 index 00000000..f3229c78 --- /dev/null +++ b/src/stubs/com/sun/tools/javac/main/Option.java @@ -0,0 +1,10 @@ +/* + * These are stub versions of various bits of javac-internal API (for various different versions of javac). Lombok is compiled against these. + */ +package com.sun.tools.javac.main; + + +public enum Option { + ; + public String text; +} diff --git a/src/stubs/com/sun/tools/javac/parser/JavaTokenizer.java b/src/stubs/com/sun/tools/javac/parser/JavaTokenizer.java new file mode 100644 index 00000000..7d5bbcb1 --- /dev/null +++ b/src/stubs/com/sun/tools/javac/parser/JavaTokenizer.java @@ -0,0 +1,19 @@ +package com.sun.tools.javac.parser; + +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; + +public class JavaTokenizer { + protected UnicodeReader reader; + + protected JavaTokenizer(ScannerFactory fac, UnicodeReader reader) { + } + + public com.sun.tools.javac.parser.Tokens.Token readToken() { + return null; + } + + protected Comment processComment(int pos, int endPos, CommentStyle style) { + return null; + } +} diff --git a/src/stubs/com/sun/tools/javac/parser/JavacParser.java b/src/stubs/com/sun/tools/javac/parser/JavacParser.java new file mode 100644 index 00000000..da42f37a --- /dev/null +++ b/src/stubs/com/sun/tools/javac/parser/JavacParser.java @@ -0,0 +1,12 @@ +package com.sun.tools.javac.parser; + +import com.sun.tools.javac.tree.JCTree; + +public class JavacParser { + protected JavacParser(ParserFactory fac, Lexer S, boolean keepDocComments, boolean keepLineMap, boolean keepEndPositions) { + } + + public JCTree.JCCompilationUnit parseCompilationUnit() { + return null; + } +} diff --git a/src/stubs/com/sun/tools/javac/parser/Scanner.java b/src/stubs/com/sun/tools/javac/parser/Scanner.java index 266208e5..36c93df7 100644 --- a/src/stubs/com/sun/tools/javac/parser/Scanner.java +++ b/src/stubs/com/sun/tools/javac/parser/Scanner.java @@ -20,6 +20,9 @@ public class Scanner implements Lexer { protected Scanner(ScannerFactory fac, char[] input, int inputLength) { } + protected Scanner(ScannerFactory fac, JavaTokenizer tokenizer) { + } + public static class Factory { public static final Context.Key<Scanner.Factory> scannerFactoryKey = null; diff --git a/src/stubs/com/sun/tools/javac/parser/Tokens.java b/src/stubs/com/sun/tools/javac/parser/Tokens.java new file mode 100644 index 00000000..6e0aa479 --- /dev/null +++ b/src/stubs/com/sun/tools/javac/parser/Tokens.java @@ -0,0 +1,21 @@ +package com.sun.tools.javac.parser; + +public class Tokens { + public static class Token { + + } + + public interface Comment { + enum CommentStyle { + LINE, BLOCK, JAVADOC, + } + + String getText(); + + int getSourcePos(int index); + + CommentStyle getStyle(); + + boolean isDeprecated(); + } +} diff --git a/src/stubs/com/sun/tools/javac/parser/UnicodeReader.java b/src/stubs/com/sun/tools/javac/parser/UnicodeReader.java new file mode 100644 index 00000000..1c09eb6b --- /dev/null +++ b/src/stubs/com/sun/tools/javac/parser/UnicodeReader.java @@ -0,0 +1,18 @@ +package com.sun.tools.javac.parser; + +import java.nio.CharBuffer; + +public class UnicodeReader { + protected int bp; + + protected UnicodeReader(ScannerFactory sf, char[] input, int inputLength) { + } + + protected UnicodeReader(ScannerFactory sf, CharBuffer buffer) { + + } + + public char[] getRawCharacters(int beginIndex, int endIndex) { + return null; + } +} diff --git a/src/stubs/com/sun/tools/javac/tree/DocCommentTable.java b/src/stubs/com/sun/tools/javac/tree/DocCommentTable.java new file mode 100644 index 00000000..75b2526a --- /dev/null +++ b/src/stubs/com/sun/tools/javac/tree/DocCommentTable.java @@ -0,0 +1,10 @@ +package com.sun.tools.javac.tree; + +import com.sun.tools.javac.parser.Tokens.Comment; + +public interface DocCommentTable { + boolean hasComment(JCTree tree); + Comment getComment(JCTree tree); + String getCommentText(JCTree tree); + void putComment(JCTree tree, Comment c); +} diff --git a/src/utils/lombok/core/debug/FileLog.java b/src/utils/lombok/core/debug/FileLog.java new file mode 100644 index 00000000..dedec40e --- /dev/null +++ b/src/utils/lombok/core/debug/FileLog.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 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 + * 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.core.debug; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class FileLog { + private static FileOutputStream fos; + + public static void log(String message) { + log(message, null); + } + public synchronized static void log(String message, Throwable t) { + try { + if (fos == null) { + fos = new FileOutputStream(new File(System.getProperty("user.home"), "LOMBOK-DEBUG-OUT.txt")); + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + try { + fos.close(); + } catch (Throwable ignore) {} + } + }); + } + fos.write(message.getBytes("UTF-8")); + fos.write('\n'); + if (t != null) { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + fos.write(sw.toString().getBytes("UTF-8")); + fos.write('\n'); + } + fos.flush(); + } catch (IOException e) { + throw new IllegalStateException("Internal lombok file-based debugging not possible", e); + } + } +} diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index 565a166d..36d90e30 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Project Lombok Authors. + * Copyright (C) 2011-2013 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,13 +21,15 @@ */ package lombok.javac; +import java.lang.reflect.InvocationTargetException; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.WeakHashMap; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; public class CommentCatcher { private final JavaCompiler compiler; @@ -55,38 +57,54 @@ public class CommentCatcher { return compiler; } + public void setComments(JCCompilationUnit ast, List<CommentInfo> comments) { + if (comments != null) { + commentsMap.put(ast, comments); + } else { + commentsMap.remove(ast); + } + } + public List<CommentInfo> getComments(JCCompilationUnit ast) { List<CommentInfo> list = commentsMap.get(ast); - return list == null ? List.<CommentInfo>nil() : list; + return list == null ? Collections.<CommentInfo>emptyList() : list; } private static void registerCommentsCollectingScannerFactory(Context context) { try { - if (Javac.getJavaCompilerVersion() <= 6) { - Class.forName("lombok.javac.java6.CommentCollectingScannerFactory").getMethod("preRegister", Context.class).invoke(null, context); + Class<?> scannerFactory; + int javaCompilerVersion = Javac.getJavaCompilerVersion(); + if (javaCompilerVersion <= 6) { + scannerFactory = Class.forName("lombok.javac.java6.CommentCollectingScannerFactory"); + } else if (javaCompilerVersion == 7) { + scannerFactory = Class.forName("lombok.javac.java7.CommentCollectingScannerFactory"); } else { - Class.forName("lombok.javac.java7.CommentCollectingScannerFactory").getMethod("preRegister", Context.class).invoke(null, context); + scannerFactory = Class.forName("lombok.javac.java8.CommentCollectingScannerFactory"); } + scannerFactory.getMethod("preRegister", Context.class).invoke(null, context); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException)e; - throw new RuntimeException(e); + throw Javac.sneakyThrow(e); } } private static void setInCompiler(JavaCompiler compiler, Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) { - try { - if (Javac.getJavaCompilerVersion() <= 6) { - Class<?> parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory"); - parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + Class<?> parserFactory; + int javaCompilerVersion = Javac.getJavaCompilerVersion(); + if (javaCompilerVersion <= 6) { + parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory"); + } else if (javaCompilerVersion == 7) { + parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory"); } else { - Class<?> parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory"); - parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + parserFactory = Class.forName("lombok.javac.java8.CommentCollectingParserFactory"); } + parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException)e; - throw new RuntimeException(e); + throw Javac.sneakyThrow(e); } } - } diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index 4f316d9f..bdf5e7a0 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -21,57 +21,105 @@ */ package lombok.javac; +import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; +import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; + import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.sun.tools.javac.code.TypeTags; +import javax.lang.model.type.NoType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeVisitor; + +import lombok.javac.JavacTreeMaker.TreeTag; +import lombok.javac.JavacTreeMaker.TypeTag; + +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.code.Type; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCLiteral; -import com.sun.tools.javac.tree.JCTree.JCModifiers; -import com.sun.tools.javac.tree.JCTree.JCTypeParameter; -import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** * Container for static utility methods relevant to lombok's operation on javac. */ public class Javac { private Javac() { - //prevent instantiation + // prevent instantiation } /** Matches any of the 8 primitive names, such as {@code boolean}. */ - private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile( - "^(boolean|byte|short|int|long|float|double|char)$"); + private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$"); private static final Pattern VERSION_PARSER = Pattern.compile("^(\\d{1,6})\\.(\\d{1,6}).*$"); + private static final Pattern SOURCE_PARSER = Pattern.compile("^JDK(\\d{1,6})_(\\d{1,6}).*$"); + + private static final AtomicInteger compilerVersion = new AtomicInteger(-1); /** * Returns the version of this java compiler, i.e. the JDK that it shipped in. For example, for javac v1.7, this returns {@code 7}. */ public static int getJavaCompilerVersion() { - Matcher m = VERSION_PARSER.matcher(JavaCompiler.version()); - if (m.matches()) { - int major = Integer.parseInt(m.group(1)); - int minor = Integer.parseInt(m.group(2)); - if (major == 1) return minor; + int cv = compilerVersion.get(); + if (cv != -1) return cv; + + /* Main algorithm: Use JavaCompiler's intended method to do this */ { + Matcher m = VERSION_PARSER.matcher(JavaCompiler.version()); + if (m.matches()) { + int major = Integer.parseInt(m.group(1)); + int minor = Integer.parseInt(m.group(2)); + if (major == 1) { + compilerVersion.set(minor); + return minor; + } + } } + /* Fallback algorithm one: Check Source's values. Lets hope oracle never releases a javac that recognizes future versions for -source */ { + String name = Source.values()[Source.values().length - 1].name(); + Matcher m = SOURCE_PARSER.matcher(name); + if (m.matches()) { + int major = Integer.parseInt(m.group(1)); + int minor = Integer.parseInt(m.group(2)); + if (major == 1) { + compilerVersion.set(minor); + return minor; + } + } + } + + compilerVersion.set(6); return 6; } + private static final Class<?> DOCCOMMENTTABLE_CLASS; + + static { + Class<?> c = null; + try { + c = Class.forName("com.sun.tools.javac.tree.DocCommentTable"); + } catch (Throwable ignore) {} + DOCCOMMENTTABLE_CLASS = c; + } + + public static boolean instanceOfDocCommentTable(Object o) { + return DOCCOMMENTTABLE_CLASS != null && DOCCOMMENTTABLE_CLASS.isInstance(o); + } + /** - * Checks if the given expression (that really ought to refer to a type expression) represents a primitive type. + * Checks if the given expression (that really ought to refer to a type + * expression) represents a primitive type. */ public static boolean isPrimitive(JCExpression ref) { String typeName = ref.toString(); @@ -79,15 +127,16 @@ public class Javac { } /** - * Turns an expression into a guessed intended literal. Only works for literals, as you can imagine. + * Turns an expression into a guessed intended literal. Only works for + * literals, as you can imagine. * * Will for example turn a TrueLiteral into 'Boolean.valueOf(true)'. */ public static Object calculateGuess(JCExpression expr) { if (expr instanceof JCLiteral) { - JCLiteral lit = (JCLiteral)expr; + JCLiteral lit = (JCLiteral) expr; if (lit.getKind() == com.sun.source.tree.Tree.Kind.BOOLEAN_LITERAL) { - return ((Number)lit.value).intValue() == 0 ? false : true; + return ((Number) lit.value).intValue() == 0 ? false : true; } return lit.value; } else if (expr instanceof JCIdent || expr instanceof JCFieldAccess) { @@ -98,102 +147,176 @@ public class Javac { if (idx > -1) x = x.substring(idx + 1); } return x; - } else return null; - } - - public static final int CTC_BOOLEAN = getCtcInt(TypeTags.class, "BOOLEAN"); - public static final int CTC_INT = getCtcInt(TypeTags.class, "INT"); - public static final int CTC_DOUBLE = getCtcInt(TypeTags.class, "DOUBLE"); - public static final int CTC_FLOAT = getCtcInt(TypeTags.class, "FLOAT"); - public static final int CTC_SHORT = getCtcInt(TypeTags.class, "SHORT"); - public static final int CTC_BYTE = getCtcInt(TypeTags.class, "BYTE"); - public static final int CTC_LONG = getCtcInt(TypeTags.class, "LONG"); - public static final int CTC_CHAR = getCtcInt(TypeTags.class, "CHAR"); - public static final int CTC_VOID = getCtcInt(TypeTags.class, "VOID"); - public static final int CTC_NONE = getCtcInt(TypeTags.class, "NONE"); - - public static final int CTC_NOT_EQUAL = getCtcInt(JCTree.class, "NE"); - public static final int CTC_NOT = getCtcInt(JCTree.class, "NOT"); - public static final int CTC_BITXOR = getCtcInt(JCTree.class, "BITXOR"); - public static final int CTC_UNSIGNED_SHIFT_RIGHT = getCtcInt(JCTree.class, "USR"); - public static final int CTC_MUL = getCtcInt(JCTree.class, "MUL"); - public static final int CTC_PLUS = getCtcInt(JCTree.class, "PLUS"); - public static final int CTC_BOT = getCtcInt(TypeTags.class, "BOT"); - public static final int CTC_EQUAL = getCtcInt(JCTree.class, "EQ"); + } else + return null; + } - /** - * Retrieves a compile time constant of type int from the specified class location. - * - * Solves the problem of compile time constant inlining, resulting in lombok having the wrong value - * (javac compiler changes private api constants from time to time) - * - * @param ctcLocation location of the compile time constant - * @param identifier the name of the field of the compile time constant. - */ - public static int getCtcInt(Class<?> ctcLocation, String identifier) { + public static final TypeTag CTC_BOOLEAN = typeTag("BOOLEAN"); + public static final TypeTag CTC_INT = typeTag("INT"); + public static final TypeTag CTC_DOUBLE = typeTag("DOUBLE"); + public static final TypeTag CTC_FLOAT = typeTag("FLOAT"); + public static final TypeTag CTC_SHORT = typeTag("SHORT"); + public static final TypeTag CTC_BYTE = typeTag("BYTE"); + public static final TypeTag CTC_LONG = typeTag("LONG"); + public static final TypeTag CTC_CHAR = typeTag("CHAR"); + public static final TypeTag CTC_VOID = typeTag("VOID"); + public static final TypeTag CTC_NONE = typeTag("NONE"); + public static final TypeTag CTC_BOT = typeTag("BOT"); + public static final TypeTag CTC_CLASS = typeTag("CLASS"); + + public static final TreeTag CTC_NOT_EQUAL = treeTag("NE"); + public static final TreeTag CTC_POS = treeTag("POS"); + public static final TreeTag CTC_NEG = treeTag("NEG"); + public static final TreeTag CTC_NOT = treeTag("NOT"); + public static final TreeTag CTC_COMPL = treeTag("COMPL"); + public static final TreeTag CTC_BITXOR = treeTag("BITXOR"); + public static final TreeTag CTC_UNSIGNED_SHIFT_RIGHT = treeTag("USR"); + public static final TreeTag CTC_MUL = treeTag("MUL"); + public static final TreeTag CTC_PLUS = treeTag("PLUS"); + public static final TreeTag CTC_EQUAL = treeTag("EQ"); + public static final TreeTag CTC_PREINC = treeTag("PREINC"); + public static final TreeTag CTC_PREDEC = treeTag("PREDEC"); + + private static final Method getExtendsClause, getEndPosition; + + static { + getExtendsClause = getMethod(JCClassDecl.class, "getExtendsClause", new Class<?>[0]); + getExtendsClause.setAccessible(true); + + if (getJavaCompilerVersion() < 8) { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", java.util.Map.class); + } else { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", "com.sun.tools.javac.tree.EndPosTable"); + } + getEndPosition.setAccessible(true); + } + + private static Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes) { try { - return (Integer)ctcLocation.getField(identifier).get(null); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + return clazz.getMethod(name, paramTypes); + } catch (NoSuchMethodException e) { + throw sneakyThrow(e); } } - private static final Field JCTREE_TAG; - private static final Method JCTREE_GETTAG; - static { - Field f = null; + private static Method getMethod(Class<?> clazz, String name, String... paramTypes) { try { - f = JCTree.class.getDeclaredField("tag"); - } catch (NoSuchFieldException e) {} - JCTREE_TAG = f; - - Method m = null; + Class<?>[] c = new Class[paramTypes.length]; + for (int i = 0; i < paramTypes.length; i++) c[i] = Class.forName(paramTypes[i]); + return clazz.getMethod(name, c); + } catch (NoSuchMethodException e) { + throw sneakyThrow(e); + } catch (ClassNotFoundException e) { + throw sneakyThrow(e); + } + } + + public static JCTree getExtendsClause(JCClassDecl decl) { try { - m = JCTree.class.getDeclaredMethod("getTag"); - } catch (NoSuchMethodException e) {} - JCTREE_GETTAG = m; + return (JCTree) getExtendsClause.invoke(decl); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } } - public static int getTag(JCTree node) { - if (JCTREE_GETTAG != null) { - try { - return (Integer) JCTREE_GETTAG.invoke(node); - } catch (Exception e) {} + public static Object getDocComments(JCCompilationUnit cu) { + try { + return JCCOMPILATIONUNIT_DOCCOMMENTS.get(cu); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } + } + + public static void initDocComments(JCCompilationUnit cu) { + try { + JCCOMPILATIONUNIT_DOCCOMMENTS.set(cu, new HashMap<Object, String>()); + } catch (IllegalArgumentException e) { + // That's fine - we're on JDK8, we'll fix that later. + } catch (IllegalAccessException e) { + throw sneakyThrow(e); } + } + + public static int getEndPosition(DiagnosticPosition pos, JCCompilationUnit top) { try { - return (Integer) JCTREE_TAG.get(node); - } catch (Exception e) { - throw new IllegalStateException("Can't get node tag"); + Object endPositions = JCCOMPILATIONUNIT_ENDPOSITIONS.get(top); + return (Integer) getEndPosition.invoke(pos, endPositions); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); } } - private static Method method; + private static final Class<?> JC_VOID_TYPE, JC_NO_TYPE; + + static { + Class<?> c = null; + try { + c = Class.forName("com.sun.tools.javac.code.Type$JCVoidType"); + } catch (Throwable ignore) {} + JC_VOID_TYPE = c; + c = null; + try { + c = Class.forName("com.sun.tools.javac.code.Type$JCNoType"); + } catch (Throwable ignore) {} + JC_NO_TYPE = c; + } - public static JCClassDecl ClassDef(TreeMaker maker, JCModifiers mods, Name name, List<JCTypeParameter> typarams, JCExpression extending, List<JCExpression> implementing, List<JCTree> defs) { - if (method == null) try { - method = TreeMaker.class.getDeclaredMethod("ClassDef", JCModifiers.class, Name.class, List.class, JCExpression.class, List.class, List.class); - } catch (NoSuchMethodException ignore) {} - if (method == null) try { - method = TreeMaker.class.getDeclaredMethod("ClassDef", JCModifiers.class, Name.class, List.class, JCTree.class, List.class, List.class); - } catch (NoSuchMethodException ignore) {} + public static Type createVoidType(JavacTreeMaker maker, TypeTag tag) { + if (Javac.getJavaCompilerVersion() < 8) { + return new JCNoType(((Integer) tag.value).intValue()); + } else { + try { + if (CTC_VOID.equals(tag)) { + return (Type) JC_VOID_TYPE.newInstance(); + } else { + return (Type) JC_NO_TYPE.newInstance(); + } + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InstantiationException e) { + throw sneakyThrow(e); + } + } + } + + private static class JCNoType extends Type implements NoType { + public JCNoType(int tag) { + super(tag, null); + } - if (method == null) throw new IllegalStateException("Lombok bug #20130617-1310: ClassDef doesn't look like anything we thought it would look like."); - if (!Modifier.isPublic(method.getModifiers()) && !method.isAccessible()) { - method.setAccessible(true); + @Override + public TypeKind getKind() { + if (tag == ((Integer) CTC_VOID.value).intValue()) return TypeKind.VOID; + if (tag == ((Integer) CTC_NONE.value).intValue()) return TypeKind.NONE; + throw new AssertionError("Unexpected tag: " + tag); } - try { - return (JCClassDecl) method.invoke(maker, mods, name, typarams, extending, implementing, defs); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } catch (IllegalAccessException e) { - throw sneakyThrow(e.getCause()); + @Override + public <R, P> R accept(TypeVisitor<R, P> v, P p) { + return v.visitNoType(this, p); } } - private static RuntimeException sneakyThrow(Throwable t) { + private static final Field JCCOMPILATIONUNIT_ENDPOSITIONS, JCCOMPILATIONUNIT_DOCCOMMENTS; + static { + Field f = null; + try { + f = JCCompilationUnit.class.getDeclaredField("endPositions"); + } catch (NoSuchFieldException e) {} + JCCOMPILATIONUNIT_ENDPOSITIONS = f; + + f = null; + try { + f = JCCompilationUnit.class.getDeclaredField("docComments"); + } catch (NoSuchFieldException e) {} + JCCOMPILATIONUNIT_DOCCOMMENTS = f; + } + + static RuntimeException sneakyThrow(Throwable t) { if (t == null) throw new NullPointerException("t"); Javac.<RuntimeException>sneakyThrow0(t); return null; diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java new file mode 100644 index 00000000..12baf5af --- /dev/null +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -0,0 +1,830 @@ +/* + * Copyright (C) 2013 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 + * 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; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.BoundKind; +import com.sun.tools.javac.code.Symbol; +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.JCArrayAccess; +import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; +import com.sun.tools.javac.tree.JCTree.JCAssert; +import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCAssignOp; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCBreak; +import com.sun.tools.javac.tree.JCTree.JCCase; +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.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCContinue; +import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; +import com.sun.tools.javac.tree.JCTree.JCErroneous; +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.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCIf; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.JCTree.JCInstanceOf; +import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCParens; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; +import com.sun.tools.javac.tree.JCTree.JCReturn; +import com.sun.tools.javac.tree.JCTree.JCSkip; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCSwitch; +import com.sun.tools.javac.tree.JCTree.JCSynchronized; +import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; +import com.sun.tools.javac.tree.JCTree.JCTypeCast; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCWildcard; +import com.sun.tools.javac.tree.JCTree.LetExpr; +import com.sun.tools.javac.tree.JCTree.TypeBoundKind; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; + +public class JavacTreeMaker { + private final TreeMaker tm; + + public JavacTreeMaker(TreeMaker tm) { + this.tm = tm; + } + + public TreeMaker getUnderlyingTreeMaker() { + return tm; + } + + public JavacTreeMaker at(int pos) { + tm.at(pos); + return this; + } + + private static class MethodId<J> { + private final Class<?> owner; + private final String name; + private final Class<J> returnType; + private final Class<?>[] paramTypes; + + MethodId(Class<?> owner, String name, Class<J> returnType, Class<?>... types) { + this.owner = owner; + this.name = name; + this.paramTypes = types; + this.returnType = returnType; + } + + @Override public String toString() { + StringBuilder out = new StringBuilder(); + out.append(returnType.getName()).append(" ").append(owner.getName()).append(".").append(name).append("("); + boolean f = true; + for (Class<?> p : paramTypes) { + if (f) f = false; + else out.append(", "); + out.append(p.getName()); + } + return out.append(")").toString(); + } + } + + private static class SchroedingerType { + final Object value; + + private SchroedingerType(Object value) { + this.value = value; + } + + @Override public int hashCode() { + return value == null ? -1 : value.hashCode(); + } + + @Override public boolean equals(Object obj) { + if (obj instanceof SchroedingerType) { + Object other = ((SchroedingerType) obj).value; + return value == null ? other == null : value.equals(other); + } + return false; + } + + static Object getFieldCached(ConcurrentMap<String, Object> cache, String className, String fieldName) { + Object value = cache.get(fieldName); + if (value != null) return value; + try { + value = Class.forName(className).getField(fieldName).get(null); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } catch (ClassNotFoundException e) { + throw Javac.sneakyThrow(e); + } + + cache.putIfAbsent(fieldName, value); + return value; + } + + private static Field NOSUCHFIELDEX_MARKER; + static { + try { + NOSUCHFIELDEX_MARKER = SchroedingerType.class.getDeclaredField("NOSUCHFIELDEX_MARKER"); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } + } + + static Object getFieldCached(ConcurrentMap<Class<?>, Field> cache, Object ref, String fieldName) throws NoSuchFieldException { + Class<?> c = ref.getClass(); + Field field = cache.get(c); + if (field == null) { + try { + field = c.getField(fieldName); + } catch (NoSuchFieldException e) { + cache.putIfAbsent(c, NOSUCHFIELDEX_MARKER); + throw Javac.sneakyThrow(e); + } + field.setAccessible(true); + Field old = cache.putIfAbsent(c, field); + if (old != null) field = old; + } + + if (field == NOSUCHFIELDEX_MARKER) throw new NoSuchFieldException(fieldName); + try { + return field.get(ref); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } + } + + public static class TypeTag extends SchroedingerType { + private static final ConcurrentMap<String, Object> TYPE_TAG_CACHE = new ConcurrentHashMap<String, Object>(); + private static final ConcurrentMap<Class<?>, Field> FIELD_CACHE = new ConcurrentHashMap<Class<?>, Field>(); + private static final Method TYPE_TYPETAG_METHOD; + + static { + Method m = null; + try { + m = Type.class.getDeclaredMethod("getTag"); + m.setAccessible(true); + } catch (NoSuchMethodException e) {} + TYPE_TYPETAG_METHOD = m; + } + + private TypeTag(Object value) { + super(value); + } + + public static TypeTag typeTag(JCTree o) { + try { + return new TypeTag(getFieldCached(FIELD_CACHE, o, "typetag")); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } + } + + public static TypeTag typeTag(Type t) { + try { + return new TypeTag(getFieldCached(FIELD_CACHE, t, "tag")); + } catch (NoSuchFieldException e) { + if (TYPE_TYPETAG_METHOD == null) throw new IllegalStateException("Type " + t.getClass() + " has neither 'tag' nor getTag()"); + try { + return new TypeTag(TYPE_TYPETAG_METHOD.invoke(t)); + } catch (IllegalAccessException ex) { + throw Javac.sneakyThrow(ex); + } catch (InvocationTargetException ex) { + throw Javac.sneakyThrow(ex.getCause()); + } + } + } + + public static TypeTag typeTag(String identifier) { + return new TypeTag(getFieldCached(TYPE_TAG_CACHE, Javac.getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTags" : "com.sun.tools.javac.code.TypeTag", identifier)); + } + } + + public static class TreeTag extends SchroedingerType { + private static final ConcurrentMap<String, Object> TREE_TAG_CACHE = new ConcurrentHashMap<String, Object>(); + private static final Field TAG_FIELD; + private static final Method TAG_METHOD; + private static final MethodId<Integer> OP_PREC = MethodId(TreeInfo.class, "opPrec", int.class, TreeTag.class); + + static { + Method m = null; + try { + m = JCTree.class.getDeclaredMethod("getTag"); + m.setAccessible(true); + } catch (NoSuchMethodException e) {} + + if (m != null) { + TAG_FIELD = null; + TAG_METHOD = m; + } else { + Field f = null; + try { + f = JCTree.class.getDeclaredField("tag"); + f.setAccessible(true); + } catch (NoSuchFieldException e) {} + TAG_FIELD = f; + TAG_METHOD = null; + } + } + + private TreeTag(Object value) { + super(value); + } + + public static TreeTag treeTag(JCTree o) { + try { + if (TAG_METHOD != null) return new TreeTag(TAG_METHOD.invoke(o)); + else return new TreeTag(TAG_FIELD.get(o)); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } + + public static TreeTag treeTag(String identifier) { + return new TreeTag(getFieldCached(TREE_TAG_CACHE, Javac.getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.tree.JCTree" : "com.sun.tools.javac.tree.JCTree$Tag", identifier)); + } + + public int getOperatorPrecedenceLevel() { + return invokeAny(null, OP_PREC, value); + } + + public boolean isPrefixUnaryOp() { + return Javac.CTC_NEG.equals(this) || Javac.CTC_POS.equals(this) || Javac.CTC_NOT.equals(this) || Javac.CTC_COMPL.equals(this) || Javac.CTC_PREDEC.equals(this) || Javac.CTC_PREINC.equals(this); + } + } + + static <J> MethodId<J> MethodId(Class<?> owner, String name, Class<J> returnType, Class<?>... types) { + return new MethodId<J>(owner, name, returnType, types); + } + + /** + * Creates a new method ID based on the name of the method to invoke, the return type of that method, and the types of the parameters. + * + * A method matches if the return type matches, and for each parameter the following holds: + * + * Either (A) the type listed here is the same as, or a subtype of, the type of the method in javac's TreeMaker, or + * (B) the type listed here is a subtype of SchroedingerType. + */ + static <J> MethodId<J> MethodId(String name, Class<J> returnType, Class<?>... types) { + return new MethodId<J>(TreeMaker.class, name, returnType, types); + } + + /** + * Creates a new method ID based on the name of a method in this class, assuming the name of the method to invoke in TreeMaker has the same name, + * the same return type, and the same parameters (under the same rules as the other MethodId method). + */ + static <J> MethodId<J> MethodId(String name) { + for (Method m : JavacTreeMaker.class.getDeclaredMethods()) { + if (m.getName().equals(name)) { + @SuppressWarnings("unchecked") Class<J> r = (Class<J>) m.getReturnType(); + Class<?>[] p = m.getParameterTypes(); + return new MethodId<J>(TreeMaker.class, name, r, p); + } + } + + throw new InternalError("Not found: " + name); + } + + private static final ConcurrentHashMap<MethodId<?>, Method> METHOD_CACHE = new ConcurrentHashMap<MethodId<?>, Method>(); + private <J> J invoke(MethodId<J> m, Object... args) { + return invokeAny(tm, m, args); + } + + @SuppressWarnings("unchecked") private static <J> J invokeAny(Object owner, MethodId<J> m, Object... args) { + Method method = METHOD_CACHE.get(m); + if (method == null) method = addToCache(m); + try { + if (m.returnType.isPrimitive()) { + Object res = method.invoke(owner, args); + String sn = res.getClass().getSimpleName().toLowerCase(); + if (!sn.startsWith(m.returnType.getSimpleName())) throw new ClassCastException(res.getClass() + " to " + m.returnType); + return (J) res; + } + return m.returnType.cast(method.invoke(owner, args)); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } catch (IllegalArgumentException e) { + System.err.println(method); + throw Javac.sneakyThrow(e); + } + } + + private static Method addToCache(MethodId<?> m) { + Method found = null; + + outer: + for (Method method : m.owner.getDeclaredMethods()) { + if (!m.name.equals(method.getName())) continue; + Class<?>[] t = method.getParameterTypes(); + if (t.length != m.paramTypes.length) continue; + for (int i = 0; i < t.length; i++) { + if (Symbol.class.isAssignableFrom(t[i])) continue outer; + if (!SchroedingerType.class.isAssignableFrom(m.paramTypes[i])) { + if (t[i].isPrimitive()) { + if (t[i] != m.paramTypes[i]) continue outer; + } else { + if (!t[i].isAssignableFrom(m.paramTypes[i])) continue outer; + } + } + } + if (found == null) found = method; + else throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); + } + if (found == null) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m); + found.setAccessible(true); + Object marker = METHOD_CACHE.putIfAbsent(m, found); + if (marker == null) return found; + return METHOD_CACHE.get(m); + } + + //javac versions: 6-8 + private static final MethodId<JCCompilationUnit> TopLevel = MethodId("TopLevel"); + public JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations, JCExpression pid, List<JCTree> defs) { + return invoke(TopLevel, packageAnnotations, pid, defs); + } + + //javac versions: 6-8 + private static final MethodId<JCImport> Import = MethodId("Import"); + public JCImport Import(JCTree qualid, boolean staticImport) { + return invoke(Import, qualid, staticImport); + } + + //javac versions: 6-8 + private static final MethodId<JCClassDecl> ClassDef = MethodId("ClassDef"); + public JCClassDecl ClassDef(JCModifiers mods, Name name, List<JCTypeParameter> typarams, JCExpression extending, List<JCExpression> implementing, List<JCTree> defs) { + return invoke(ClassDef, mods, name, typarams, extending, implementing, defs); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodDecl> MethodDef = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, List.class, List.class, JCBlock.class, JCExpression.class); + public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDef, mods, name, resType, typarams, params, thrown, body, defaultValue); + } + + //javac versions: 8 + private static final MethodId<JCMethodDecl> MethodDefWithRecvParam = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, JCVariableDecl.class, List.class, List.class, JCBlock.class, JCExpression.class); + public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, JCVariableDecl recvparam, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDefWithRecvParam, mods, name, resType, recvparam, typarams, params, thrown, body, defaultValue); + } + + //javac versions: 6-8 + private static final MethodId<JCVariableDecl> VarDef = MethodId("VarDef"); + public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init) { + return invoke(VarDef, mods, name, vartype, init); + } + + //javac versions: 8 + private static final MethodId<JCVariableDecl> ReceiverVarDef = MethodId("ReceiverVarDef"); + public JCVariableDecl ReceiverVarDef(JCModifiers mods, JCExpression name, JCExpression vartype) { + return invoke(ReceiverVarDef, mods, name, vartype); + } + + //javac versions: 6-8 + private static final MethodId<JCSkip> Skip = MethodId("Skip"); + public JCSkip Skip() { + return invoke(Skip); + } + + //javac versions: 6-8 + private static final MethodId<JCBlock> Block = MethodId("Block"); + public JCBlock Block(long flags, List<JCStatement> stats) { + return invoke(Block, flags, stats); + } + + //javac versions: 6-8 + private static final MethodId<JCDoWhileLoop> DoLoop = MethodId("DoLoop"); + public JCDoWhileLoop DoLoop(JCStatement body, JCExpression cond) { + return invoke(DoLoop, body, cond); + } + + //javac versions: 6-8 + private static final MethodId<JCWhileLoop> WhileLoop = MethodId("WhileLoop"); + public JCWhileLoop WhileLoop(JCExpression cond, JCStatement body) { + return invoke(WhileLoop, cond, body); + } + + //javac versions: 6-8 + private static final MethodId<JCForLoop> ForLoop = MethodId("ForLoop"); + public JCForLoop ForLoop(List<JCStatement> init, JCExpression cond, List<JCExpressionStatement> step, JCStatement body) { + return invoke(ForLoop, init, cond, step, body); + } + + //javac versions: 6-8 + private static final MethodId<JCEnhancedForLoop> ForeachLoop = MethodId("ForeachLoop"); + public JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body) { + return invoke(ForeachLoop, var, expr, body); + } + + //javac versions: 6-8 + private static final MethodId<JCLabeledStatement> Labelled = MethodId("Labelled"); + public JCLabeledStatement Labelled(Name label, JCStatement body) { + return invoke(Labelled, label, body); + } + + //javac versions: 6-8 + private static final MethodId<JCSwitch> Switch = MethodId("Switch"); + public JCSwitch Switch(JCExpression selector, List<JCCase> cases) { + return invoke(Switch, selector, cases); + } + + //javac versions: 6-8 + private static final MethodId<JCCase> Case = MethodId("Case"); + public JCCase Case(JCExpression pat, List<JCStatement> stats) { + return invoke(Case, pat, stats); + } + + //javac versions: 6-8 + private static final MethodId<JCSynchronized> Synchronized = MethodId("Synchronized"); + public JCSynchronized Synchronized(JCExpression lock, JCBlock body) { + return invoke(Synchronized, lock, body); + } + + //javac versions: 6-8 + private static final MethodId<JCTry> Try = MethodId("Try", JCTry.class, JCBlock.class, List.class, JCBlock.class); + public JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer) { + return invoke(Try, body, catchers, finalizer); + } + + //javac versions: 7-8 + private static final MethodId<JCTry> TryWithResources = MethodId("Try", JCTry.class, List.class, JCBlock.class, List.class, JCBlock.class); + public JCTry Try(List<JCTree> resources, JCBlock body, List<JCCatch> catchers, JCBlock finalizer) { + return invoke(TryWithResources, resources, body, catchers, finalizer); + } + + //javac versions: 6-8 + private static final MethodId<JCCatch> Catch = MethodId("Catch"); + public JCCatch Catch(JCVariableDecl param, JCBlock body) { + return invoke(Catch, param, body); + } + + //javac versions: 6-8 + private static final MethodId<JCConditional> Conditional = MethodId("Conditional"); + public JCConditional Conditional(JCExpression cond, JCExpression thenpart, JCExpression elsepart) { + return invoke(Conditional, cond, thenpart, elsepart); + } + + //javac versions: 6-8 + private static final MethodId<JCIf> If = MethodId("If"); + public JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart) { + return invoke(If, cond, thenpart, elsepart); + } + + //javac versions: 6-8 + private static final MethodId<JCExpressionStatement> Exec = MethodId("Exec"); + public JCExpressionStatement Exec(JCExpression expr) { + return invoke(Exec, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCBreak> Break = MethodId("Break"); + public JCBreak Break(Name label) { + return invoke(Break, label); + } + + //javac versions: 6-8 + private static final MethodId<JCContinue> Continue = MethodId("Continue"); + public JCContinue Continue(Name label) { + return invoke(Continue, label); + } + + //javac versions: 6-8 + private static final MethodId<JCReturn> Return = MethodId("Return"); + public JCReturn Return(JCExpression expr) { + return invoke(Return, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCThrow> Throw = MethodId("Throw"); + public JCThrow Throw(JCExpression expr) { + return invoke(Throw, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCAssert> Assert = MethodId("Assert"); + public JCAssert Assert(JCExpression cond, JCExpression detail) { + return invoke(Assert, cond, detail); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodInvocation> Apply = MethodId("Apply"); + public JCMethodInvocation Apply(List<JCExpression> typeargs, JCExpression fn, List<JCExpression> args) { + return invoke(Apply, typeargs, fn, args); + } + + //javac versions: 6-8 + private static final MethodId<JCNewClass> NewClass = MethodId("NewClass"); + public JCNewClass NewClass(JCExpression encl, List<JCExpression> typeargs, JCExpression clazz, List<JCExpression> args, JCClassDecl def) { + return invoke(NewClass, encl, typeargs, clazz, args, def); + } + + //javac versions: 6-8 + private static final MethodId<JCNewArray> NewArray = MethodId("NewArray"); + public JCNewArray NewArray(JCExpression elemtype, List<JCExpression> dims, List<JCExpression> elems) { + return invoke(NewArray, elemtype, dims, elems); + } + + //javac versions: 8 +// private static final MethodId<JCLambda> Lambda = MethodId("Lambda"); +// public JCLambda Lambda(List<JCVariableDecl> params, JCTree body) { +// return invoke(Lambda, params, body); +// } + + //javac versions: 6-8 + private static final MethodId<JCParens> Parens = MethodId("Parens"); + public JCParens Parens(JCExpression expr) { + return invoke(Parens, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCAssign> Assign = MethodId("Assign"); + public JCAssign Assign(JCExpression lhs, JCExpression rhs) { + return invoke(Assign, lhs, rhs); + } + + //javac versions: 6-8 + //opcode = [6-7] int [8] JCTree.Tag + private static final MethodId<JCAssignOp> Assignop = MethodId("Assignop"); + public JCAssignOp Assignop(TreeTag opcode, JCTree lhs, JCTree rhs) { + return invoke(Assignop, opcode.value, lhs, rhs); + } + + //javac versions: 6-8 + //opcode = [6-7] int [8] JCTree.Tag + private static final MethodId<JCUnary> Unary = MethodId("Unary"); + public JCUnary Unary(TreeTag opcode, JCExpression arg) { + return invoke(Unary, opcode.value, arg); + } + + //javac versions: 6-8 + //opcode = [6-7] int [8] JCTree.Tag + private static final MethodId<JCBinary> Binary = MethodId("Binary"); + public JCBinary Binary(TreeTag opcode, JCExpression lhs, JCExpression rhs) { + return invoke(Binary, opcode.value, lhs, rhs); + } + + //javac versions: 6-8 + private static final MethodId<JCTypeCast> TypeCast = MethodId("TypeCast"); + public JCTypeCast TypeCast(JCTree expr, JCExpression type) { + return invoke(TypeCast, expr, type); + } + + //javac versions: 6-8 + private static final MethodId<JCInstanceOf> TypeTest = MethodId("TypeTest"); + public JCInstanceOf TypeTest(JCExpression expr, JCTree clazz) { + return invoke(TypeTest, expr, clazz); + } + + //javac versions: 6-8 + private static final MethodId<JCArrayAccess> Indexed = MethodId("Indexed"); + public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) { + return invoke(Indexed, indexed, index); + } + + //javac versions: 6-8 + private static final MethodId<JCFieldAccess> Select = MethodId("Select"); + public JCFieldAccess Select(JCExpression selected, Name selector) { + return invoke(Select, selected, selector); + } + + //javac versions: 8 +// private static final MethodId<JCMemberReference> Reference = MethodId("Reference"); +// public JCMemberReference Reference(JCMemberReference.ReferenceMode mode, Name name, JCExpression expr, List<JCExpression> typeargs) { +// return invoke(Reference, mode, name, expr, typeargs); +// } + + //javac versions: 6-8 + private static final MethodId<JCIdent> Ident = MethodId("Ident", JCIdent.class, Name.class); + public JCIdent Ident(Name idname) { + return invoke(Ident, idname); + } + + //javac versions: 6-8 + //tag = [6-7] int [8] TypeTag + private static final MethodId<JCLiteral> Literal = MethodId("Literal", JCLiteral.class, TypeTag.class, Object.class); + public JCLiteral Literal(TypeTag tag, Object value) { + return invoke(Literal, tag.value, value); + } + + //javac versions: 6-8 + //typetag = [6-7] int [8] TypeTag + private static final MethodId<JCPrimitiveTypeTree> TypeIdent = MethodId("TypeIdent"); + public JCPrimitiveTypeTree TypeIdent(TypeTag typetag) { + return invoke(TypeIdent, typetag.value); + } + //javac versions: 6-8 + private static final MethodId<JCArrayTypeTree> TypeArray = MethodId("TypeArray"); + public JCArrayTypeTree TypeArray(JCExpression elemtype) { + return invoke(TypeArray, elemtype); + } + + //javac versions: 6-8 + private static final MethodId<JCTypeApply> TypeApply = MethodId("TypeApply"); + public JCTypeApply TypeApply(JCExpression clazz, List<JCExpression> arguments) { + return invoke(TypeApply, clazz, arguments); + } + + //javac versions: 7-8 +// private static final MethodId<JCTypeUnion> TypeUnion = MethodId("TypeUnion"); +// public JCTypeUnion TypeUnion(List<JCExpression> components) { +// return invoke(TypeUnion, compoonents); +// } + + //javac versions: 8 +// private static final MethodId<JCTypeIntersection> TypeIntersection = MethodId("TypeIntersection"); +// public JCTypeIntersection TypeIntersection(List<JCExpression> components) { +// return invoke(TypeIntersection, components); +// } + + //javac versions: 6-8 + private static final MethodId<JCTypeParameter> TypeParameter = MethodId("TypeParameter", JCTypeParameter.class, Name.class, List.class); + public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds) { + return invoke(TypeParameter, name, bounds); + } + + //javac versions: 8 + private static final MethodId<JCTypeParameter> TypeParameterWithAnnos = MethodId("TypeParameter", JCTypeParameter.class, Name.class, List.class, List.class); + public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds, List<JCAnnotation> annos) { + return invoke(TypeParameterWithAnnos, name, bounds, annos); + } + + //javac versions: 6-8 + private static final MethodId<JCWildcard> Wildcard = MethodId("Wildcard"); + public JCWildcard Wildcard(TypeBoundKind kind, JCTree type) { + return invoke(Wildcard, kind, type); + } + + //javac versions: 6-8 + private static final MethodId<TypeBoundKind> TypeBoundKind = MethodId("TypeBoundKind"); + public TypeBoundKind TypeBoundKind(BoundKind kind) { + return invoke(TypeBoundKind, kind); + } + + //javac versions: 6-8 + private static final MethodId<JCAnnotation> Annotation = MethodId("Annotation", JCAnnotation.class, JCTree.class, List.class); + public JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args) { + return invoke(Annotation, annotationType, args); + } + + //javac versions: 8 + private static final MethodId<JCAnnotation> TypeAnnotation = MethodId("TypeAnnotation", JCAnnotation.class, JCTree.class, List.class); + public JCAnnotation TypeAnnotation(JCTree annotationType, List<JCExpression> args) { + return invoke(TypeAnnotation, annotationType, args); + } + + //javac versions: 6-8 + private static final MethodId<JCModifiers> ModifiersWithAnnotations = MethodId("Modifiers", JCModifiers.class, long.class, List.class); + public JCModifiers Modifiers(long flags, List<JCAnnotation> annotations) { + return invoke(ModifiersWithAnnotations, flags, annotations); + } + + //javac versions: 6-8 + private static final MethodId<JCModifiers> Modifiers = MethodId("Modifiers", JCModifiers.class, long.class); + public JCModifiers Modifiers(long flags) { + return invoke(Modifiers, flags); + } + + //javac versions: 8 +// private static final MethodId<JCAnnotatedType> AnnotatedType = MethodId("AnnotatedType"); +// public JCAnnotatedType AnnotatedType(List<JCAnnotation> annotations, JCExpression underlyingType) { +// return invoke(AnnotatedType, annotations, underlyingType); +// } + + //javac versions: 6-8 + private static final MethodId<JCErroneous> Erroneous = MethodId("Erroneous", JCErroneous.class); + public JCErroneous Erroneous() { + return invoke(Erroneous); + } + + //javac versions: 6-8 + private static final MethodId<JCErroneous> ErroneousWithErrs = MethodId("Erroneous", JCErroneous.class, List.class); + public JCErroneous Erroneous(List<? extends JCTree> errs) { + return invoke(ErroneousWithErrs, errs); + } + + //javac versions: 6-8 + private static final MethodId<LetExpr> LetExpr = MethodId("LetExpr", LetExpr.class, List.class, JCTree.class); + public LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr) { + return invoke(LetExpr, defs, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCClassDecl> AnonymousClassDef = MethodId("AnonymousClassDef"); + public JCClassDecl AnonymousClassDef(JCModifiers mods, List<JCTree> defs) { + return invoke(AnonymousClassDef, mods, defs); + } + + //javac versions: 6-8 + private static final MethodId<LetExpr> LetExprSingle = MethodId("LetExpr", LetExpr.class, JCVariableDecl.class, JCTree.class); + public LetExpr LetExpr(JCVariableDecl def, JCTree expr) { + return invoke(LetExprSingle, def, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCIdent> IdentVarDecl = MethodId("Ident", JCIdent.class, JCVariableDecl.class); + public JCExpression Ident(JCVariableDecl param) { + return invoke(IdentVarDecl, param); + } + + //javac versions: 6-8 + private static final MethodId<List<JCExpression>> Idents = MethodId("Idents"); + public List<JCExpression> Idents(List<JCVariableDecl> params) { + return invoke(Idents, params); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodInvocation> App2 = MethodId("App", JCMethodInvocation.class, JCExpression.class, List.class); + public JCMethodInvocation App(JCExpression meth, List<JCExpression> args) { + return invoke(App2, meth, args); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodInvocation> App1 = MethodId("App", JCMethodInvocation.class, JCExpression.class); + public JCMethodInvocation App(JCExpression meth) { + return invoke(App1, meth); + } + + //javac versions: 6-8 + private static final MethodId<List<JCAnnotation>> Annotations = MethodId("Annotations"); + public List<JCAnnotation> Annotations(List<Attribute.Compound> attributes) { + return invoke(Annotations, attributes); + } + + //javac versions: 6-8 + private static final MethodId<JCLiteral> LiteralWithValue = MethodId("Literal", JCLiteral.class, Object.class); + public JCLiteral Literal(Object value) { + return invoke(LiteralWithValue, value); + } + + //javac versions: 6-8 + private static final MethodId<JCAnnotation> AnnotationWithAttributeOnly = MethodId("Annotation", JCAnnotation.class, Attribute.class); + public JCAnnotation Annotation(Attribute a) { + return invoke(AnnotationWithAttributeOnly, a); + } + + //javac versions: 8 + private static final MethodId<JCAnnotation> TypeAnnotationWithAttributeOnly = MethodId("TypeAnnotation", JCAnnotation.class, Attribute.class); + public JCAnnotation TypeAnnotation(Attribute a) { + return invoke(TypeAnnotationWithAttributeOnly, a); + } + + //javac versions: 6-8 + private static final MethodId<JCStatement> Call = MethodId("Call"); + public JCStatement Call(JCExpression apply) { + return invoke(Call, apply); + } + + //javac versions: 6-8 + private static final MethodId<JCExpression> Type = MethodId("Type"); + public JCExpression Type(Type type) { + return invoke(Type, type); + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/TreeMirrorMaker.java b/src/utils/lombok/javac/TreeMirrorMaker.java index 30915572..23ec2406 100644 --- a/src/utils/lombok/javac/TreeMirrorMaker.java +++ b/src/utils/lombok/javac/TreeMirrorMaker.java @@ -31,7 +31,6 @@ import com.sun.source.tree.VariableTree; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeCopier; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; /** @@ -47,8 +46,8 @@ import com.sun.tools.javac.util.List; public class TreeMirrorMaker extends TreeCopier<Void> { private final IdentityHashMap<JCTree, JCTree> originalToCopy = new IdentityHashMap<JCTree, JCTree>(); - public TreeMirrorMaker(TreeMaker maker) { - super(maker); + public TreeMirrorMaker(JavacTreeMaker maker) { + super(maker.getUnderlyingTreeMaker()); } @Override public <T extends JCTree> T copy(T original) { diff --git a/src/utils/lombok/javac/java6/CommentCollectingParser.java b/src/utils/lombok/javac/java6/CommentCollectingParser.java index 94a85e55..30192b06 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingParser.java +++ b/src/utils/lombok/javac/java6/CommentCollectingParser.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2013 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 + * 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.java6; import java.util.Map; diff --git a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java index 7e34b723..b250b898 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java +++ b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2013 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 + * 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.java6; import java.lang.reflect.Field; diff --git a/src/utils/lombok/javac/java6/CommentCollectingScanner.java b/src/utils/lombok/javac/java6/CommentCollectingScanner.java index b584ec16..df383b93 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingScanner.java +++ b/src/utils/lombok/javac/java6/CommentCollectingScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Project Lombok Authors. + * Copyright (C) 2011-2013 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 @@ -27,11 +27,12 @@ import lombok.javac.CommentInfo; import lombok.javac.CommentInfo.EndConnection; import lombok.javac.CommentInfo.StartConnection; +import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; -public class CommentCollectingScanner extends DocCommentScanner { - private final ListBuffer<CommentInfo> comments = ListBuffer.lb(); +public class CommentCollectingScanner extends Scanner { + private final ListBuffer<CommentInfo> comments = new ListBuffer<CommentInfo>(); private int endComment = 0; public CommentCollectingScanner(CommentCollectingScannerFactory factory, CharBuffer charBuffer) { diff --git a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java index f3d6bd72..b7d8ed13 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java +++ b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java @@ -26,7 +26,7 @@ import java.nio.CharBuffer; import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.util.Context; -public class CommentCollectingScannerFactory extends DocCommentScanner.Factory { +public class CommentCollectingScannerFactory extends Scanner.Factory { @SuppressWarnings("all") public static void preRegister(final Context context) { diff --git a/src/utils/lombok/javac/java6/DocCommentScanner.java b/src/utils/lombok/javac/java6/DocCommentScanner.java deleted file mode 100644 index ff3eadd4..00000000 --- a/src/utils/lombok/javac/java6/DocCommentScanner.java +++ /dev/null @@ -1,461 +0,0 @@ -package lombok.javac.java6; - -/* - * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -import static com.sun.tools.javac.util.LayoutCharacters.*; - -import java.nio.CharBuffer; - -import com.sun.tools.javac.parser.Scanner; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Position; - -/** An extension to the base lexical analyzer that captures - * and processes the contents of doc comments. It does so by - * translating Unicode escape sequences and by stripping the - * leading whitespace and starts from each line of the comment. - * - * <p><b>This is NOT part of any API supported by Sun Microsystems. If - * you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice.</b> - */ -public class DocCommentScanner extends Scanner { - - /** A factory for creating scanners. */ - public static class Factory extends Scanner.Factory { - - @SuppressWarnings({"unchecked", "all"}) - public static void preRegister(final Context context) { - context.put(scannerFactoryKey, new Context.Factory() { - public Object make() { - return new Factory(context); - } - - public Object make(Context c) { - return new Factory(c); - } - }); - } - - /** Create a new scanner factory. */ - protected Factory(Context context) { - super(context); - } - - @Override - public Scanner newScanner(CharSequence input) { - if (input instanceof CharBuffer) { - return new DocCommentScanner(this, (CharBuffer)input); - } else { - char[] array = input.toString().toCharArray(); - return newScanner(array, array.length); - } - } - - @Override - public Scanner newScanner(char[] input, int inputLength) { - return new DocCommentScanner(this, input, inputLength); - } - } - - - /** Create a scanner from the input buffer. buffer must implement - * array() and compact(), and remaining() must be less than limit(). - */ - protected DocCommentScanner(Factory fac, CharBuffer buffer) { - super(fac, buffer); - } - - /** Create a scanner from the input array. The array must have at - * least a single character of extra space. - */ - protected DocCommentScanner(Factory fac, char[] input, int inputLength) { - super(fac, input, inputLength); - } - - /** Starting position of the comment in original source - */ - private int pos; - - /** The comment input buffer, index of next chacter to be read, - * index of one past last character in buffer. - */ - private char[] buf; - private int bp; - private int buflen; - - /** The current character. - */ - private char ch; - - /** The column number position of the current character. - */ - private int col; - - /** The buffer index of the last converted Unicode character - */ - private int unicodeConversionBp = 0; - - /** - * Buffer for doc comment. - */ - private char[] docCommentBuffer = new char[1024]; - - /** - * Number of characters in doc comment buffer. - */ - private int docCommentCount; - - /** - * Translated and stripped contents of doc comment - */ - private String docComment = null; - - - /** Unconditionally expand the comment buffer. - */ - private void expandCommentBuffer() { - char[] newBuffer = new char[docCommentBuffer.length * 2]; - System.arraycopy(docCommentBuffer, 0, newBuffer, - 0, docCommentBuffer.length); - docCommentBuffer = newBuffer; - } - - /** Convert an ASCII digit from its base (8, 10, or 16) - * to its value. - */ - private int digit(int base) { - char c = ch; - int result = Character.digit(c, base); - if (result >= 0 && c > 0x7f) { - ch = "0123456789abcdef".charAt(result); - } - return result; - } - - /** Convert Unicode escape; bp points to initial '\' character - * (Spec 3.3). - */ - private void convertUnicode() { - if (ch == '\\' && unicodeConversionBp != bp) { - bp++; ch = buf[bp]; col++; - if (ch == 'u') { - do { - bp++; ch = buf[bp]; col++; - } while (ch == 'u'); - int limit = bp + 3; - if (limit < buflen) { - int d = digit(16); - int code = d; - while (bp < limit && d >= 0) { - bp++; ch = buf[bp]; col++; - d = digit(16); - code = (code << 4) + d; - } - if (d >= 0) { - ch = (char)code; - unicodeConversionBp = bp; - return; - } - } - // "illegal.Unicode.esc", reported by base scanner - } else { - bp--; - ch = '\\'; - col--; - } - } - } - - - /** Read next character. - */ - private void scanChar() { - bp++; - ch = buf[bp]; - switch (ch) { - case '\r': // return - col = 0; - break; - case '\n': // newline - if (bp == 0 || buf[bp-1] != '\r') { - col = 0; - } - break; - case '\t': // tab - col = (col / TabInc * TabInc) + TabInc; - break; - case '\\': // possible Unicode - col++; - convertUnicode(); - break; - default: - col++; - break; - } - } - - /** - * Read next character in doc comment, skipping over double '\' characters. - * If a double '\' is skipped, put in the buffer and update buffer count. - */ - private void scanDocCommentChar() { - scanChar(); - if (ch == '\\') { - if (buf[bp+1] == '\\' && unicodeConversionBp != bp) { - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - bp++; col++; - } else { - convertUnicode(); - } - } - } - - /* Reset doc comment before reading each new token - */ - public void nextToken() { - docComment = null; - super.nextToken(); - } - - /** - * Returns the documentation string of the current token. - */ - public String docComment() { - return docComment; - } - - /** - * Process a doc comment and make the string content available. - * Strips leading whitespace and stars. - */ - @SuppressWarnings("fallthrough") - protected void processComment(CommentStyle style) { - if (style != CommentStyle.JAVADOC) { - return; - } - - pos = pos(); - buf = getRawCharacters(pos, endPos()); - buflen = buf.length; - bp = 0; - col = 0; - - docCommentCount = 0; - - boolean firstLine = true; - - // Skip over first slash - scanDocCommentChar(); - // Skip over first star - scanDocCommentChar(); - - // consume any number of stars - while (bp < buflen && ch == '*') { - scanDocCommentChar(); - } - // is the comment in the form /**/, /***/, /****/, etc. ? - if (bp < buflen && ch == '/') { - docComment = ""; - return; - } - - // skip a newline on the first line of the comment. - if (bp < buflen) { - if (ch == LF) { - scanDocCommentChar(); - firstLine = false; - } else if (ch == CR) { - scanDocCommentChar(); - if (ch == LF) { - scanDocCommentChar(); - firstLine = false; - } - } - } - - outerLoop: - - // The outerLoop processes the doc comment, looping once - // for each line. For each line, it first strips off - // whitespace, then it consumes any stars, then it - // puts the rest of the line into our buffer. - while (bp < buflen) { - - // The wsLoop consumes whitespace from the beginning - // of each line. - wsLoop: - - while (bp < buflen) { - switch(ch) { - case ' ': - scanDocCommentChar(); - break; - case '\t': - col = ((col - 1) / TabInc * TabInc) + TabInc; - scanDocCommentChar(); - break; - case FF: - col = 0; - scanDocCommentChar(); - break; -// Treat newline at beginning of line (blank line, no star) -// as comment text. Old Javadoc compatibility requires this. -/*---------------------------------* - case CR: // (Spec 3.4) - scanDocCommentChar(); - if (ch == LF) { - col = 0; - scanDocCommentChar(); - } - break; - case LF: // (Spec 3.4) - scanDocCommentChar(); - break; -*---------------------------------*/ - default: - // we've seen something that isn't whitespace; - // jump out. - break wsLoop; - } - } - - // Are there stars here? If so, consume them all - // and check for the end of comment. - if (ch == '*') { - // skip all of the stars - do { - scanDocCommentChar(); - } while (ch == '*'); - - // check for the closing slash. - if (ch == '/') { - // We're done with the doc comment - // scanChar() and breakout. - break outerLoop; - } - } else if (! firstLine) { - //The current line does not begin with a '*' so we will indent it. - for (int i = 1; i < col; i++) { - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ' '; - } - } - - // The textLoop processes the rest of the characters - // on the line, adding them to our buffer. - textLoop: - while (bp < buflen) { - switch (ch) { - case '*': - // Is this just a star? Or is this the - // end of a comment? - scanDocCommentChar(); - if (ch == '/') { - // This is the end of the comment, - // set ch and return our buffer. - break outerLoop; - } - // This is just an ordinary star. Add it to - // the buffer. - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = '*'; - break; - case ' ': - case '\t': - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - scanDocCommentChar(); - break; - case FF: - scanDocCommentChar(); - break textLoop; // treat as end of line - case CR: // (Spec 3.4) - scanDocCommentChar(); - if (ch != LF) { - // Canonicalize CR-only line terminator to LF - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = (char)LF; - break textLoop; - } - /* fall through to LF case */ - case LF: // (Spec 3.4) - // We've seen a newline. Add it to our - // buffer and break out of this loop, - // starting fresh on a new line. - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - scanDocCommentChar(); - break textLoop; - default: - // Add the character to our buffer. - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - scanDocCommentChar(); - } - } // end textLoop - firstLine = false; - } // end outerLoop - - if (docCommentCount > 0) { - int i = docCommentCount - 1; - trailLoop: - while (i > -1) { - switch (docCommentBuffer[i]) { - case '*': - i--; - break; - default: - break trailLoop; - } - } - docCommentCount = i + 1; - - // Store the text of the doc comment - docComment = new String(docCommentBuffer, 0 , docCommentCount); - } else { - docComment = ""; - } - } - - /** Build a map for translating between line numbers and - * positions in the input. - * - * @return a LineMap */ - public Position.LineMap getLineMap() { - char[] buf = getRawCharacters(); - return Position.makeLineMap(buf, buf.length, true); - } -} diff --git a/src/utils/lombok/javac/java7/CommentCollectingParser.java b/src/utils/lombok/javac/java7/CommentCollectingParser.java index 82f19c42..0e8a4ef6 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingParser.java +++ b/src/utils/lombok/javac/java7/CommentCollectingParser.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2013 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 + * 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.java7; import java.util.List; diff --git a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java index e9575c14..ed8279df 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java +++ b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2013 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 + * 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.java7; import java.lang.reflect.Field; diff --git a/src/utils/lombok/javac/java7/CommentCollectingScanner.java b/src/utils/lombok/javac/java7/CommentCollectingScanner.java index 6ebd3ac1..3f76f910 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingScanner.java +++ b/src/utils/lombok/javac/java7/CommentCollectingScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Project Lombok Authors. + * Copyright (C) 2011-2013 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 @@ -27,12 +27,12 @@ import lombok.javac.CommentInfo; import lombok.javac.CommentInfo.EndConnection; import lombok.javac.CommentInfo.StartConnection; +import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.parser.DocCommentScanner; -public class CommentCollectingScanner extends DocCommentScanner { - private final ListBuffer<CommentInfo> comments = ListBuffer.lb(); +public class CommentCollectingScanner extends Scanner { + private final ListBuffer<CommentInfo> comments = new ListBuffer<CommentInfo>(); private int endComment = 0; public CommentCollectingScanner(CommentCollectingScannerFactory factory, CharBuffer charBuffer) { diff --git a/src/utils/lombok/javac/java8/CommentCollectingParser.java b/src/utils/lombok/javac/java8/CommentCollectingParser.java new file mode 100644 index 00000000..e305e44f --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingParser.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 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 + * 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.java8; + +import java.util.List; +import java.util.Map; + +import lombok.javac.CommentInfo; + +import com.sun.tools.javac.parser.JavacParser; +import com.sun.tools.javac.parser.Lexer; +import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; + +class CommentCollectingParser extends JavacParser { + private final Map<JCCompilationUnit, List<CommentInfo>> commentsMap; + private final Lexer lexer; + + protected CommentCollectingParser(ParserFactory fac, Lexer S, + boolean keepDocComments, boolean keepLineMap, boolean keepEndPositions, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) { + super(fac, S, keepDocComments, keepLineMap, keepEndPositions); + lexer = S; + this.commentsMap = commentsMap; + } + + public JCCompilationUnit parseCompilationUnit() { + JCCompilationUnit result = super.parseCompilationUnit(); + if (lexer instanceof CommentCollectingScanner) { + List<CommentInfo> comments = ((CommentCollectingScanner)lexer).getComments(); + commentsMap.put(result, comments); + } + return result; + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java8/CommentCollectingParserFactory.java new file mode 100644 index 00000000..6b5f9198 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingParserFactory.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 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 + * 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.java8; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +import lombok.javac.CommentInfo; + +import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.parser.JavacParser; +import com.sun.tools.javac.parser.Lexer; +import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.parser.ScannerFactory; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.util.Context; + +public class CommentCollectingParserFactory extends ParserFactory { + private final Map<JCCompilationUnit, List<CommentInfo>> commentsMap; + private final Context context; + + static Context.Key<ParserFactory> key() { + return parserFactoryKey; + } + + protected CommentCollectingParserFactory(Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) { + super(context); + this.context = context; + this.commentsMap = commentsMap; + } + + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) { + ScannerFactory scannerFactory = ScannerFactory.instance(context); + Lexer lexer = scannerFactory.newScanner(input, true); + Object x = new CommentCollectingParser(this, lexer, true, keepLineMap, keepEndPos, commentsMap); + return (JavacParser) x; + // CCP is based on a stub which extends nothing, but at runtime the stub is replaced with either + //javac6's EndPosParser which extends Parser, or javac8's JavacParser which implements Parser. + //Either way this will work out. + } + + public static void setInCompiler(JavaCompiler compiler, Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) { + context.put(CommentCollectingParserFactory.key(), (ParserFactory)null); + Field field; + try { + field = JavaCompiler.class.getDeclaredField("parserFactory"); + field.setAccessible(true); + field.set(compiler, new CommentCollectingParserFactory(context, commentsMap)); + } catch (Exception e) { + throw new IllegalStateException("Could not set comment sensitive parser in the compiler", e); + } + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingScanner.java b/src/utils/lombok/javac/java8/CommentCollectingScanner.java new file mode 100644 index 00000000..b59a9390 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingScanner.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 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 + * 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.java8; + +import lombok.javac.CommentInfo; + +import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.parser.ScannerFactory; +import com.sun.tools.javac.util.List; + +public class CommentCollectingScanner extends Scanner { + + private CommentCollectingTokenizer tokenizer; + + public CommentCollectingScanner(ScannerFactory fac, CommentCollectingTokenizer tokenizer) { + super(fac, tokenizer); + this.tokenizer = tokenizer; + } + + public List<CommentInfo> getComments() { + return tokenizer.getComments(); + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java new file mode 100644 index 00000000..fa79ff67 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2011-2013 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 + * 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.java8; + +import java.nio.CharBuffer; + +import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.parser.ScannerFactory; +import com.sun.tools.javac.util.Context; + +public class CommentCollectingScannerFactory extends ScannerFactory { + + @SuppressWarnings("all") + public static void preRegister(final Context context) { + if (context.get(scannerFactoryKey) == null) { + // Careful! There is voodoo magic here! + // + // Context.Factory is parameterized. make() is for javac6 and below; make(Context) is for javac7 and up. + // this anonymous inner class definition is intentionally 'raw' - the return type of both 'make' methods is 'T', + // which means the compiler will only generate the correct "real" override method (with returntype Object, which is + // the lower bound for T, as a synthetic accessor for the make with returntype ScannerFactory) for that make method which + // is actually on the classpath (either make() for javac6-, or make(Context) for javac7+). + // + // We normally solve this issue via src/stubs, with BOTH make methods listed, but for some reason the presence of a stubbed out + // Context (or even a complete copy, it doesn't matter) results in a really strange eclipse bug, where any mention of any kind + // of com.sun.tools.javac.tree.TreeMaker in a source file disables ALL usage of 'go to declaration' and auto-complete in the entire + // source file. + // + // Thus, in short: + // * Do NOT parameterize the anonymous inner class literal. + // * Leave the return types as 'j.l.Object'. + // * Leave both make methods intact; deleting one has no effect on javac6- / javac7+, but breaks the other. Hard to test for. + // * Do not stub com.sun.tools.javac.util.Context or any of its inner types, like Factory. + @SuppressWarnings("all") + class MyFactory implements Context.Factory { + // This overrides the javac6- version of make. + public Object make() { + return new CommentCollectingScannerFactory(context); + } + + // This overrides the javac7+ version. + public Object make(Context c) { + return new CommentCollectingScannerFactory(c); + } + } + @SuppressWarnings("unchecked") Context.Factory<ScannerFactory> factory = new MyFactory(); + context.put(scannerFactoryKey, factory); + } + } + + /** Create a new scanner factory. */ + protected CommentCollectingScannerFactory(Context context) { + super(context); + } + + @Override + public Scanner newScanner(CharSequence input, boolean keepDocComments) { + if (input instanceof CharBuffer) { + CharBuffer buf = (CharBuffer) input; + return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, buf)); + } + char[] array = input.toString().toCharArray(); + return newScanner(array, array.length, keepDocComments); + } + + @Override + public Scanner newScanner(char[] input, int inputLength, boolean keepDocComments) { + return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, input, inputLength)); + } +} diff --git a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java new file mode 100644 index 00000000..1834fb00 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2013 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 + * 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.java8; + +import java.nio.CharBuffer; + +import lombok.javac.CommentInfo; +import lombok.javac.CommentInfo.EndConnection; +import lombok.javac.CommentInfo.StartConnection; + +import com.sun.tools.javac.parser.JavaTokenizer; +import com.sun.tools.javac.parser.ScannerFactory; +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.parser.Tokens.Token; +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; +import com.sun.tools.javac.parser.UnicodeReader; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; + +class CommentCollectingTokenizer extends JavaTokenizer { + private int prevEndPosition = 0; + private final ListBuffer<CommentInfo> comments = new ListBuffer<CommentInfo>(); + private int endComment = 0; + + CommentCollectingTokenizer(ScannerFactory fac, char[] buf, int inputLength) { + super(fac, new PositionUnicodeReader(fac, buf, inputLength)); + } + + CommentCollectingTokenizer(ScannerFactory fac, CharBuffer buf) { + super(fac, new PositionUnicodeReader(fac, buf)); + } + + @Override public Token readToken() { + Token token = super.readToken(); + prevEndPosition = ((PositionUnicodeReader)reader).pos(); + return token; + } + + @Override + protected Comment processComment(int pos, int endPos, CommentStyle style) { + int prevEndPos = Math.max(prevEndPosition, endComment); + endComment = endPos; + String content = new String(reader.getRawCharacters(pos, endPos)); + StartConnection start = determineStartConnection(prevEndPos, pos); + EndConnection end = determineEndConnection(endPos); + + CommentInfo comment = new CommentInfo(prevEndPos, pos, endPos, content, start, end); + comments.append(comment); + + return super.processComment(pos, endPos, style); + } + + private EndConnection determineEndConnection(int pos) { + boolean first = true; + for (int i = pos;; i++) { + char c; + try { + c = reader.getRawCharacters(i, i + 1)[0]; + } catch (IndexOutOfBoundsException e) { + c = '\n'; + } + if (isNewLine(c)) { + return EndConnection.ON_NEXT_LINE; + } + if (Character.isWhitespace(c)) { + first = false; + continue; + } + return first ? EndConnection.DIRECT_AFTER_COMMENT : EndConnection.AFTER_COMMENT; + } + } + + private StartConnection determineStartConnection(int from, int to) { + if (from == to) { + return StartConnection.DIRECT_AFTER_PREVIOUS; + } + char[] between = reader.getRawCharacters(from, to); + if (isNewLine(between[between.length - 1])) { + return StartConnection.START_OF_LINE; + } + for (char c : between) { + if (isNewLine(c)) { + return StartConnection.ON_NEXT_LINE; + } + } + return StartConnection.AFTER_PREVIOUS; + } + + private boolean isNewLine(char c) { + return c == '\n' || c == '\r'; + } + + public List<CommentInfo> getComments() { + return comments.toList(); + } + + static class PositionUnicodeReader extends UnicodeReader { + protected PositionUnicodeReader(ScannerFactory sf, char[] input, int inputLength) { + super(sf, input, inputLength); + } + + public PositionUnicodeReader(ScannerFactory sf, CharBuffer buffer) { + super(sf, buffer); + } + + int pos() { + return bp; + } + } +}
\ No newline at end of file |