diff options
author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2010-11-09 20:37:25 +0100 |
---|---|---|
committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2010-11-09 20:37:25 +0100 |
commit | 46d471e9c3dc32b03c34804df1819739a4dffc50 (patch) | |
tree | 9c31d75426bf8fdb1943bef2a996485640f7bf5e | |
parent | 92b7efac48c18f22b81098cf1d844a891bb71648 (diff) | |
parent | 98d8a9f63b3183005174abb7691a1692347b9a2e (diff) | |
download | lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.tar.gz lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.tar.bz2 lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.zip |
Merge branch 'master' into annoGetSet
137 files changed, 3905 insertions, 546 deletions
diff --git a/buildScripts/ivy-repo/projectlombok.org-lombok.patcher-0.3.xml b/buildScripts/ivy-repo/projectlombok.org-lombok.patcher-0.4.xml index ea9e369e..25ed9cba 100644 --- a/buildScripts/ivy-repo/projectlombok.org-lombok.patcher-0.3.xml +++ b/buildScripts/ivy-repo/projectlombok.org-lombok.patcher-0.4.xml @@ -1,5 +1,5 @@ <ivy-module version="2.0"> - <info organisation="projectlombok.org" module="lombok.patcher" revision="0.3" publication="20100225011200"> + <info organisation="projectlombok.org" module="lombok.patcher" revision="0.4" publication="20101108232300"> <license name="MIT License" url="http://www.opensource.org/licenses/mit-license.php" /> <ivyauthor name="rzwitserloot" url="http://zwitserloot.com/" /> <ivyauthor name="rspilker" url="http://github.com/rspilker" /> @@ -9,6 +9,6 @@ <conf name="build" /> </configurations> <publications> - <artifact conf="build" url="http://projectlombok.org/downloads/lombok.patcher-0.3.jar" /> + <artifact conf="build" url="http://projectlombok.org/downloads/lombok.patcher-0.4.jar" /> </publications> </ivy-module> diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml index 8e0e9f1e..25f21928 100644 --- a/buildScripts/ivy.xml +++ b/buildScripts/ivy.xml @@ -9,10 +9,13 @@ <conf name="contrib" /> </configurations> <dependencies> - <dependency org="projectlombok.org" name="lombok.patcher" rev="0.3" conf="build; runtime->build" /> + <dependency org="projectlombok.org" name="lombok.patcher" rev="0.4" conf="build; runtime->build" /> <dependency org="zwitserloot.com" name="cmdreader" rev="1.2" conf="build->runtime; runtime" /> <dependency org="projectlombok.org" name="junit" rev="4.8.1" conf="test" /> + <dependency org="log4j" name="log4j" rev="1.2.16" conf="test->master"/> + <dependency org="commons-logging" name="commons-logging" rev="1.1.1" conf="test->master"/> + <dependency org="org.slf4j" name="slf4j-api" rev="1.6.1" conf="test->master"/> <dependency org="org.apache.ant" name="ant" rev="1.8.0" conf="build->master" /> <dependency org="projectlombok.org" name="spi" rev="0.2.4" conf="build" /> diff --git a/buildScripts/website.ant.xml b/buildScripts/website.ant.xml index 73700a82..08fc8a55 100644 --- a/buildScripts/website.ant.xml +++ b/buildScripts/website.ant.xml @@ -1,5 +1,5 @@ <!-- - Copyright © 2010 Reinier Zwitserloot and Roel Spilker. + Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -132,6 +132,9 @@ such as converting the changelog into HTML, and creating javadoc. <antcall target="-integrateSnippet"> <param name="transformationName" value="Constructor" /> </antcall> + <antcall target="-integrateSnippet"> + <param name="transformationName" value="Log" /> + </antcall> </target> <target name="-website-dist"> @@ -289,7 +292,7 @@ such as converting the changelog into HTML, and creating javadoc. <classpath refid="build.path" /> <link href="http://java.sun.com/javase/6/docs/api/" offline="true" packagelistLoc="./deps/javadoc/java6"/> <header><![CDATA[<a href='http://projectlombok.org/'>Lombok</a> - ]]>v${lombok.version}</header> - <bottom><![CDATA[<i>Copyright © 2009 Reinier Zwitserloot and Roel Spilker, licensed under the <a href='http://www.opensource.org/licenses/mit-license.php'>MIT licence</a>.]]></bottom> + <bottom><![CDATA[<i>Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans, licensed under the <a href='http://www.opensource.org/licenses/mit-license.php'>MIT licence</a>.]]></bottom> </javadoc> <mkdir dir="doc/api" /> <copy todir="doc/api"> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index d203dc44..43a1eb9d 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,11 +1,14 @@ Lombok Changelog ---------------- -### v0.9.4 (edge) +### v0.9.4 "Burning Emu" (edge) +* FEATURE: Added support for several logging frameworks by the `@Log` annotation. * FEATURE: Lombok now supports post-compile transformers. [Issue #144](http://code.google.com/p/projectlombok/issues/detail?id=144) * FEATURE: Using `@SneakyThrows` no longer requires a runtime dependency on lombok.jar. In fact, any call to {@code Lombok.sneakyThrows(ex)} is optimized at the bytecode level and no longer requires you to actually have lombok.jar or lombok-runtime.jar on the classpath. * BUGFIX: `@Setter` and `@Getter` can now be applied to static fields again (was broken in v0.9.3 only). [Issue #136](http://code.google.com/p/projectlombok/issues/detail?id=136) * BUGFIX: delombok added type parameters to constructors that mirror the type's own type parameters. This resulted in delombok turning any generated constructor that takes at least 1 parameter of type 'T' into something that didn't compile, and to boot, a confusing error message ('T is not compatible with T'). This is now fixed. [Issue #140](http://code.google.com/p/projectlombok/issues/detail?id=140) +* BUGFIX: Add null check for `@Cleanup` [Issue #154](http://code.google.com/p/projectlombok/issues/detail?id=154) +* BUGFIX: The Eclipse source generator would place the generated code outside the class [Issue #154](http://code.google.com/p/projectlombok/issues/detail?id=155) ### v0.9.3 "Burrowing Whale" (July 25th, 2010) * FEATURE: Adding `@Getter` or `@Setter` to a class is now legal and is like adding those annotations to every non-static field in it. [Issue #129](http://code.google.com/p/projectlombok/issues/detail?id=129) diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java index 7e71b248..8ea554a1 100644 --- a/src/core/lombok/core/AST.java +++ b/src/core/lombok/core/AST.java @@ -65,7 +65,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, this.imports = Collections.unmodifiableCollection(new ArrayList<String>(imports)); } - protected void setChanged() { + public void setChanged() { this.changed = true; } diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java index db4c6d09..6cecedc7 100644 --- a/src/core/lombok/core/AnnotationValues.java +++ b/src/core/lombok/core/AnnotationValues.java @@ -53,29 +53,20 @@ public class AnnotationValues<A extends Annotation> { /** Guesses for each raw expression. If the raw expression is a literal expression, the guess will * likely be right. If not, it'll be wrong. */ public final List<Object> valueGuesses; + + /** A list of the actual expressions. List is size 1 unless an array is provided. */ + public final List<Object> expressions; + private final LombokNode<?, ?, ?> node; private final boolean isExplicit; /** - * 'raw' should be the exact expression, for example '5+7', 'AccessLevel.PUBLIC', or 'int.class'. - * 'valueGuess' should be a likely guess at the real value intended. - * - * For classes, supply the class name (qualified or not) as a string.<br /> - * For enums, supply the simple name part (everything after the last dot) as a string.<br /> - */ - public AnnotationValue(LombokNode<?, ?, ?> node, String raw, Object valueGuess, boolean isExplicit) { - this.node = node; - this.raws = Collections.singletonList(raw); - this.valueGuesses = Collections.singletonList(valueGuess); - this.isExplicit = isExplicit; - } - - /** * Like the other constructor, but used for when the annotation method is initialized with an array value. */ - public AnnotationValue(LombokNode<?, ?, ?> node, List<String> raws, List<Object> valueGuesses, boolean isExplicit) { + public AnnotationValue(LombokNode<?, ?, ?> node, List<String> raws, List<Object> expressions, List<Object> valueGuesses, boolean isExplicit) { this.node = node; this.raws = raws; + this.expressions = expressions; this.valueGuesses = valueGuesses; this.isExplicit = isExplicit; } @@ -310,6 +301,14 @@ public class AnnotationValues<A extends Annotation> { return v == null ? Collections.<String>emptyList() : v.raws; } + /** + * Returns the actual expressions used for the provided {@code annotationMethodName}. + */ + public List<Object> getActualExpressions(String annotationMethodName) { + AnnotationValue v = values.get(annotationMethodName); + return v == null ? Collections.<Object>emptyList() : v.expressions; + } + public boolean isExplicit(String annotationMethodName) { AnnotationValue annotationValue = values.get(annotationMethodName); return annotationValue != null && annotationValue.isExplicit(); @@ -325,6 +324,16 @@ public class AnnotationValues<A extends Annotation> { return l.isEmpty() ? null : l.get(0); } + /** + * Convenience method to return the first result in a {@link #getActualExpressions(String)} call. + * + * You should use this method if the annotation method is not an array type. + */ + public Object getActualExpression(String annotationMethodName) { + List<Object> l = getActualExpressions(annotationMethodName); + return l.isEmpty() ? null : l.get(0); + } + /** Generates an error message on the stated annotation value (you should only call this method if you know it's there!) */ public void setError(String annotationMethodName, String message) { setError(annotationMethodName, message, -1); diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java index 6d0f3147..4a57e080 100644 --- a/src/core/lombok/core/LombokNode.java +++ b/src/core/lombok/core/LombokNode.java @@ -78,6 +78,10 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A, this.isStructurallySignificant = calculateIsStructurallySignificant(null); } + public A getAst() { + return ast; + } + /** {@inheritDoc} */ @Override public String toString() { return String.format("NODE %s (%s) %s%s", diff --git a/src/core/lombok/core/handlers/SneakyThrowsAndCleanupDependencyInfo.java b/src/core/lombok/core/handlers/SneakyThrowsAndCleanupDependencyInfo.java new file mode 100644 index 00000000..4370d218 --- /dev/null +++ b/src/core/lombok/core/handlers/SneakyThrowsAndCleanupDependencyInfo.java @@ -0,0 +1,45 @@ +/* + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.handlers; + +import java.util.Arrays; +import java.util.List; + +import lombok.core.runtimeDependencies.RuntimeDependencyInfo; + +import org.mangosdk.spi.ProviderFor; + +@ProviderFor(RuntimeDependencyInfo.class) +public class SneakyThrowsAndCleanupDependencyInfo implements RuntimeDependencyInfo { + @Override public List<String> getRuntimeDependencies() { + return Arrays.asList( + "lombok/Lombok.class" + ); + } + + @Override public List<String> getRuntimeDependentsDescriptions() { + return Arrays.asList( + "@SneakyThrows (only when delomboking - using @SneakyThrows in code that is compiled with lombok on the classpath does not create the dependency)", + "@Cleanup (only when delomboking - using @Cleanup in code that is compiled with lombok on the classpath does not create the dependency)" + ); + } +} diff --git a/src/core/lombok/eclipse/Eclipse.java b/src/core/lombok/eclipse/Eclipse.java index c70660f4..f5b80552 100644 --- a/src/core/lombok/eclipse/Eclipse.java +++ b/src/core/lombok/eclipse/Eclipse.java @@ -25,10 +25,12 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; import lombok.core.AnnotationValues; import lombok.core.TypeLibrary; @@ -62,7 +64,13 @@ import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; +import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; import org.osgi.framework.Bundle; public class Eclipse { @@ -156,7 +164,6 @@ public class Eclipse { return result; } - /** * You can't share TypeParameter objects or bad things happen; for example, one 'T' resolves differently * from another 'T', even for the same T in a single class file. Unfortunately the TypeParameter type hierarchy @@ -292,6 +299,159 @@ public class Eclipse { return ref; } + private static long pos(ASTNode node) { + return ((long) node.sourceStart << 32) | (node.sourceEnd & 0xFFFFFFFFL); + } + + public static long[] poss(ASTNode node, int repeat) { + long p = ((long) node.sourceStart << 32) | (node.sourceEnd & 0xFFFFFFFFL); + long[] out = new long[repeat]; + Arrays.fill(out, p); + return out; + } + + public static TypeReference makeType(TypeBinding binding, ASTNode pos, boolean allowCompound) { + int dims = binding.dimensions(); + binding = binding.leafComponentType(); + + // Primitives + + char[] base = null; + + switch (binding.id) { + case TypeIds.T_int: + base = TypeConstants.INT; + break; + case TypeIds.T_long: + base = TypeConstants.LONG; + break; + case TypeIds.T_short: + base = TypeConstants.SHORT; + break; + case TypeIds.T_byte: + base = TypeConstants.BYTE; + break; + case TypeIds.T_double: + base = TypeConstants.DOUBLE; + break; + case TypeIds.T_float: + base = TypeConstants.FLOAT; + break; + case TypeIds.T_boolean: + base = TypeConstants.BOOLEAN; + break; + case TypeIds.T_char: + base = TypeConstants.CHAR; + break; + case TypeIds.T_void: + base = TypeConstants.VOID; + break; + case TypeIds.T_null: + return null; + } + + if (base != null) { + if (dims > 0) { + return new ArrayTypeReference(base, dims, pos(pos)); + } + return new SingleTypeReference(base, pos(pos)); + } + + if (binding.isAnonymousType()) { + ReferenceBinding ref = (ReferenceBinding)binding; + ReferenceBinding[] supers = ref.superInterfaces(); + if (supers == null || supers.length == 0) supers = new ReferenceBinding[] {ref.superclass()}; + if (supers[0] == null) return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3)); + return makeType(supers[0], pos, false); + } + + if (binding instanceof CaptureBinding) { + return makeType(((CaptureBinding)binding).wildcard, pos, allowCompound); + } + + if (binding.isUnboundWildcard()) { + if (!allowCompound) { + return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3)); + } else { + Wildcard out = new Wildcard(Wildcard.UNBOUND); + out.sourceStart = pos.sourceStart; + out.sourceEnd = pos.sourceEnd; + return out; + } + } + + if (binding.isWildcard()) { + WildcardBinding wildcard = (WildcardBinding) binding; + if (wildcard.boundKind == Wildcard.EXTENDS) { + if (!allowCompound) { + return makeType(wildcard.bound, pos, false); + } else { + Wildcard out = new Wildcard(Wildcard.EXTENDS); + out.bound = makeType(wildcard.bound, pos, false); + out.sourceStart = pos.sourceStart; + out.sourceEnd = pos.sourceEnd; + return out; + } + } else if (allowCompound && wildcard.boundKind == Wildcard.SUPER) { + Wildcard out = new Wildcard(Wildcard.SUPER); + out.bound = makeType(wildcard.bound, pos, false); + out.sourceStart = pos.sourceStart; + out.sourceEnd = pos.sourceEnd; + return out; + } else { + return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3)); + } + } + + char[][] parts; + + if (binding.isLocalType() || binding.isTypeVariable()) { + parts = new char[][] { binding.shortReadableName() }; + } else { + String[] pkg = new String(binding.qualifiedPackageName()).split("\\."); + String[] name = new String(binding.qualifiedSourceName()).split("\\."); + if (pkg.length == 1 && pkg[0].isEmpty()) pkg = new String[0]; + parts = new char[pkg.length + name.length][]; + int ptr; + for (ptr = 0; ptr < pkg.length; ptr++) parts[ptr] = pkg[ptr].toCharArray(); + for (; ptr < pkg.length + name.length; ptr++) parts[ptr] = name[ptr - pkg.length].toCharArray(); + } + + TypeReference[] params = new TypeReference[0]; + + if (binding instanceof ParameterizedTypeBinding) { + ParameterizedTypeBinding paramized = (ParameterizedTypeBinding) binding; + if (paramized.arguments != null) { + params = new TypeReference[paramized.arguments.length]; + for (int i = 0; i < params.length; i++) { + params[i] = makeType(paramized.arguments[i], pos, true); + } + } + } + + if (params.length > 0) { + if (parts.length > 1) { + TypeReference[][] typeArguments = new TypeReference[parts.length][]; + typeArguments[typeArguments.length - 1] = params; + return new ParameterizedQualifiedTypeReference(parts, typeArguments, dims, poss(pos, parts.length)); + } + return new ParameterizedSingleTypeReference(parts[0], params, dims, pos(pos)); + } + + if (dims > 0) { + if (parts.length > 1) { + return new ArrayQualifiedTypeReference(parts, dims, poss(pos, parts.length)); + } + return new ArrayTypeReference(parts[0], dims, pos(pos)); + } + + if (parts.length > 1) { + return new QualifiedTypeReference(parts, poss(pos, parts.length)); + } + return new SingleTypeReference(parts[0], pos(pos)); + + } + public static Annotation[] copyAnnotations(Annotation[] annotations, ASTNode source) { return copyAnnotations(annotations, null, source); } @@ -377,6 +537,7 @@ public class Eclipse { if (!Modifier.isPublic(m.getModifiers())) continue; String name = m.getName(); List<String> raws = new ArrayList<String>(); + List<Object> expressionValues = new ArrayList<Object>(); List<Object> guesses = new ArrayList<Object>(); Expression fullExpression = null; Expression[] expressions = null; @@ -397,6 +558,7 @@ public class Eclipse { StringBuffer sb = new StringBuffer(); ex.print(0, sb); raws.add(sb.toString()); + expressionValues.add(ex); guesses.add(calculateValue(ex)); } } @@ -404,7 +566,7 @@ public class Eclipse { final Expression fullExpr = fullExpression; final Expression[] exprs = expressions; - values.put(name, new AnnotationValue(annotationNode, raws, guesses, isExplicit) { + values.put(name, new AnnotationValue(annotationNode, raws, expressionValues, guesses, isExplicit) { @Override public void setError(String message, int valueIdx) { Expression ex; if (valueIdx == -1) ex = fullExpr; @@ -474,12 +636,16 @@ public class Eclipse { } } + private static Map<ASTNode, ASTNode> generatedNodes = new WeakHashMap<ASTNode, ASTNode>(); + public static ASTNode getGeneratedBy(ASTNode node) { - try { - return (ASTNode) generatedByField.get(node); - } catch (Exception t) { - //ignore - no $generatedBy exists when running in ecj. - return null; + if (generatedByField != null) { + try { + return (ASTNode) generatedByField.get(node); + } catch (Exception e) {} + } + synchronized (generatedNodes) { + return generatedNodes.get(node); } } @@ -488,12 +654,15 @@ public class Eclipse { } public static ASTNode setGeneratedBy(ASTNode node, ASTNode source) { - try { - generatedByField.set(node, source); - } catch (Exception t) { - //ignore - no $generatedBy exists when running in ecj. + if (generatedByField != null) { + try { + generatedByField.set(node, source); + return node; + } catch (Exception e) {} + } + synchronized (generatedNodes) { + generatedNodes.put(node, source); } - return node; } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 5005752b..019ae637 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -23,6 +23,7 @@ package lombok.eclipse.handlers; import static lombok.eclipse.Eclipse.*; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -42,6 +43,7 @@ import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.Clinit; import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; @@ -406,9 +408,17 @@ public class EclipseHandlerUtil { /** * Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}. + * The field carries the @{@link SuppressWarnings}("all") annotation. */ - public static void injectField(EclipseNode type, FieldDeclaration field) { + public static void injectFieldSuppressWarnings(EclipseNode type, FieldDeclaration field) { field.annotations = createSuppressWarningsAll(field, field.annotations); + injectField(type, field); + } + + /** + * Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}. + */ + public static void injectField(EclipseNode type, FieldDeclaration field) { TypeDeclaration parent = (TypeDeclaration) type.get(); if (parent.fields == null) { @@ -421,9 +431,24 @@ public class EclipseHandlerUtil { parent.fields = newArray; } + if ((field.modifiers & Modifier.STATIC) != 0) { + if (!hasClinit(parent)) { + parent.addClinit(); + } + } + type.add(field, Kind.FIELD).recursiveSetHandled(); } + private static boolean hasClinit(TypeDeclaration parent) { + if (parent.methods == null) return false; + + for (AbstractMethodDeclaration method : parent.methods) { + if (method instanceof Clinit) return true; + } + return false; + } + /** * Inserts a method into an existing type. The type must represent a {@code TypeDeclaration}. */ @@ -435,25 +460,42 @@ public class EclipseHandlerUtil { parent.methods = new AbstractMethodDeclaration[1]; parent.methods[0] = method; } else { - boolean injectionComplete = false; if (method instanceof ConstructorDeclaration) { for (int i = 0 ; i < parent.methods.length ; i++) { if (parent.methods[i] instanceof ConstructorDeclaration && (parent.methods[i].bits & ASTNode.IsDefaultConstructor) != 0) { EclipseNode tossMe = type.getNodeFor(parent.methods[i]); - parent.methods[i] = method; + + AbstractMethodDeclaration[] withoutGeneratedConstructor = new AbstractMethodDeclaration[parent.methods.length - 1]; + + System.arraycopy(parent.methods, 0, withoutGeneratedConstructor, 0, i); + System.arraycopy(parent.methods, i + 1, withoutGeneratedConstructor, i, parent.methods.length - i - 1); + + parent.methods = withoutGeneratedConstructor; if (tossMe != null) tossMe.up().removeChild(tossMe); - injectionComplete = true; break; } } } - if (!injectionComplete) { - AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1]; - System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length); - newArray[parent.methods.length] = method; - parent.methods = newArray; + int insertionPoint; + for (insertionPoint = 0; insertionPoint < parent.methods.length; insertionPoint++) { + AbstractMethodDeclaration current = parent.methods[insertionPoint]; + if (current instanceof Clinit) continue; + if (method instanceof ConstructorDeclaration) { + if (current instanceof ConstructorDeclaration) continue; + break; + } + if (Eclipse.isGenerated(current)) continue; + break; + } + AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1]; + System.arraycopy(parent.methods, 0, newArray, 0, insertionPoint); + if (insertionPoint <= parent.methods.length) { + System.arraycopy(parent.methods, insertionPoint, newArray, insertionPoint + 1, parent.methods.length - insertionPoint); } + + newArray[insertionPoint] = method; + parent.methods = newArray; } type.add(method, Kind.METHOD).recursiveSetHandled(); diff --git a/src/core/lombok/eclipse/handlers/HandleCleanup.java b/src/core/lombok/eclipse/handlers/HandleCleanup.java index d296e96b..33ab7fb9 100644 --- a/src/core/lombok/eclipse/handlers/HandleCleanup.java +++ b/src/core/lombok/eclipse/handlers/HandleCleanup.java @@ -37,9 +37,13 @@ import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.CaseStatement; import org.eclipse.jdt.internal.compiler.ast.CastExpression; +import org.eclipse.jdt.internal.compiler.ast.EqualExpression; +import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; import org.eclipse.jdt.internal.compiler.ast.MessageSend; +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.SwitchStatement; @@ -157,7 +161,29 @@ public class HandleCleanup implements EclipseAnnotationHandler<Cleanup> { } unsafeClose.nameSourcePosition = nameSourcePosition; unsafeClose.selector = cleanupName.toCharArray(); - finallyBlock[0] = unsafeClose; + + + int pS = ast.sourceStart, pE = ast.sourceEnd; + long p = (long)pS << 32 | pE; + + SingleNameReference varName = new SingleNameReference(decl.name, p); + Eclipse.setGeneratedBy(varName, ast); + NullLiteral nullLiteral = new NullLiteral(pS, pE); + Eclipse.setGeneratedBy(nullLiteral, ast); + EqualExpression equalExpression = new EqualExpression(varName, nullLiteral, OperatorIds.NOT_EQUAL); + equalExpression.sourceStart = pS; equalExpression.sourceEnd = pE; + Eclipse.setGeneratedBy(equalExpression, ast); + + Block closeBlock = new Block(0); + closeBlock.statements = new Statement[1]; + closeBlock.statements[0] = unsafeClose; + Eclipse.setGeneratedBy(closeBlock, ast); + IfStatement ifStatement = new IfStatement(equalExpression, closeBlock, 0, 0); + Eclipse.setGeneratedBy(ifStatement, ast); + + + + finallyBlock[0] = ifStatement; tryStatement.finallyBlock = new Block(0); Eclipse.setGeneratedBy(tryStatement.finallyBlock, ast); tryStatement.finallyBlock.statements = finallyBlock; diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index e501c3f1..ed13fd1b 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -47,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FalseLiteral; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.IfStatement; +import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; @@ -202,9 +203,13 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA } } + boolean needsCanEqual = false; switch (methodExists("equals", typeNode)) { case NOT_EXISTS: - MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly); + boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0; + needsCanEqual = !isDirectDescendantOfObject || !isFinal; + + MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly, needsCanEqual); injectMethod(typeNode, equals); break; case EXISTS_BY_LOMBOK: @@ -217,6 +222,19 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA break; } + if (needsCanEqual) { + switch (methodExists("canEqual", typeNode)) { + case NOT_EXISTS: + MethodDeclaration equals = createCanEqual(typeNode, errorNode.get()); + injectMethod(typeNode, equals); + break; + case EXISTS_BY_LOMBOK: + case EXISTS_BY_USER: + default: + break; + } + } + switch (methodExists("hashCode", typeNode)) { case NOT_EXISTS: MethodDeclaration hashCode = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly); @@ -415,9 +433,10 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA return method; } - private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly) { + private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly, boolean needsCanEqual) { int pS = source.sourceStart; int pE = source.sourceEnd; long p = (long)pS << 32 | pE; + TypeDeclaration typeDecl = (TypeDeclaration)type.get(); MethodDeclaration method = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); @@ -458,75 +477,36 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA statements.add(ifOtherEqualsThis); } - /* if (o == null) return false; */ { + /* if (!(o instanceof MyType) return false; */ { SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); Eclipse.setGeneratedBy(oRef, source); - NullLiteral nullLiteral = new NullLiteral(pS, pE); - Eclipse.setGeneratedBy(nullLiteral, source); - EqualExpression otherEqualsNull = new EqualExpression(oRef, nullLiteral, OperatorIds.EQUAL_EQUAL); - Eclipse.setGeneratedBy(otherEqualsNull, source); + + SingleTypeReference typeReference = new SingleTypeReference(typeDecl.name, p); + Eclipse.setGeneratedBy(typeReference, source); + + InstanceOfExpression instanceOf = new InstanceOfExpression(oRef, typeReference); + instanceOf.sourceStart = pS; instanceOf.sourceEnd = pE; + Eclipse.setGeneratedBy(instanceOf, source); + + Expression notInstanceOf = new UnaryExpression(instanceOf, OperatorIds.NOT); + Eclipse.setGeneratedBy(notInstanceOf, source); FalseLiteral falseLiteral = new FalseLiteral(pS, pE); Eclipse.setGeneratedBy(falseLiteral, source); + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifOtherEqualsNull = new IfStatement(otherEqualsNull, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifOtherEqualsNull, source); - statements.add(ifOtherEqualsNull); - } - - /* if (o.getClass() != getClass()) return false; */ { - MessageSend otherGetClass = new MessageSend(); - otherGetClass.sourceStart = pS; otherGetClass.sourceEnd = pE; - Eclipse.setGeneratedBy(otherGetClass, source); - otherGetClass.receiver = new SingleNameReference(new char[] { 'o' }, p); - Eclipse.setGeneratedBy(otherGetClass.receiver, source); - otherGetClass.selector = "getClass".toCharArray(); - MessageSend thisGetClass = new MessageSend(); - thisGetClass.sourceStart = pS; thisGetClass.sourceEnd = pE; - Eclipse.setGeneratedBy(thisGetClass, source); - thisGetClass.receiver = new ThisReference(pS, pE); - Eclipse.setGeneratedBy(thisGetClass.receiver, source); - thisGetClass.selector = "getClass".toCharArray(); - EqualExpression classesNotEqual = new EqualExpression(otherGetClass, thisGetClass, OperatorIds.NOT_EQUAL); - Eclipse.setGeneratedBy(classesNotEqual, source); - FalseLiteral falseLiteral = new FalseLiteral(pS, pE); - Eclipse.setGeneratedBy(falseLiteral, source); - ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); - Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifClassesNotEqual = new IfStatement(classesNotEqual, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifClassesNotEqual, source); - statements.add(ifClassesNotEqual); + + IfStatement ifNotInstanceOf = new IfStatement(notInstanceOf, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifNotInstanceOf, source); + statements.add(ifNotInstanceOf); } - char[] otherN = "other".toCharArray(); - - /* if (!super.equals(o)) return false; */ - if (callSuper) { - MessageSend callToSuper = new MessageSend(); - callToSuper.sourceStart = pS; callToSuper.sourceEnd = pE; - Eclipse.setGeneratedBy(callToSuper, source); - callToSuper.receiver = new SuperReference(pS, pE); - Eclipse.setGeneratedBy(callToSuper.receiver, source); - callToSuper.selector = "equals".toCharArray(); - SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); - Eclipse.setGeneratedBy(oRef, source); - callToSuper.arguments = new Expression[] {oRef}; - Expression superNotEqual = new UnaryExpression(callToSuper, OperatorIds.NOT); - Eclipse.setGeneratedBy(superNotEqual, source); - FalseLiteral falseLiteral = new FalseLiteral(pS, pE); - Eclipse.setGeneratedBy(falseLiteral, source); - ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); - Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifSuperEquals = new IfStatement(superNotEqual, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifSuperEquals, source); - statements.add(ifSuperEquals); - } + char[] otherName = "other".toCharArray(); - TypeDeclaration typeDecl = (TypeDeclaration)type.get(); /* MyType<?> other = (MyType<?>) o; */ { if (!fields.isEmpty()) { - LocalDeclaration other = new LocalDeclaration(otherN, pS, pE); + LocalDeclaration other = new LocalDeclaration(otherName, pS, pE); other.modifiers |= ClassFileConstants.AccFinal; Eclipse.setGeneratedBy(other, source); char[] typeName = typeDecl.name; @@ -556,11 +536,63 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA } } + /* if (!other.canEqual(this)) return false; */ { + if (needsCanEqual) { + MessageSend otherCanEqual = new MessageSend(); + otherCanEqual.sourceStart = pS; otherCanEqual.sourceEnd = pE; + Eclipse.setGeneratedBy(otherCanEqual, source); + otherCanEqual.receiver = new SingleNameReference(otherName, p); + Eclipse.setGeneratedBy(otherCanEqual.receiver, source); + otherCanEqual.selector = "canEqual".toCharArray(); + + ThisReference thisReference = new ThisReference(pS, pE); + Eclipse.setGeneratedBy(thisReference, source); + + otherCanEqual.arguments = new Expression[] {thisReference}; + + Expression notOtherCanEqual = new UnaryExpression(otherCanEqual, OperatorIds.NOT); + Eclipse.setGeneratedBy(notOtherCanEqual, source); + + FalseLiteral falseLiteral = new FalseLiteral(pS, pE); + Eclipse.setGeneratedBy(falseLiteral, source); + + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); + Eclipse.setGeneratedBy(returnFalse, source); + + IfStatement ifNotCanEqual = new IfStatement(notOtherCanEqual, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifNotCanEqual, source); + + statements.add(ifNotCanEqual); + } + } + + /* if (!super.equals(o)) return false; */ + if (callSuper) { + MessageSend callToSuper = new MessageSend(); + callToSuper.sourceStart = pS; callToSuper.sourceEnd = pE; + Eclipse.setGeneratedBy(callToSuper, source); + callToSuper.receiver = new SuperReference(pS, pE); + Eclipse.setGeneratedBy(callToSuper.receiver, source); + callToSuper.selector = "equals".toCharArray(); + SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); + Eclipse.setGeneratedBy(oRef, source); + callToSuper.arguments = new Expression[] {oRef}; + Expression superNotEqual = new UnaryExpression(callToSuper, OperatorIds.NOT); + Eclipse.setGeneratedBy(superNotEqual, source); + FalseLiteral falseLiteral = new FalseLiteral(pS, pE); + Eclipse.setGeneratedBy(falseLiteral, source); + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); + Eclipse.setGeneratedBy(returnFalse, source); + IfStatement ifSuperEquals = new IfStatement(superNotEqual, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifSuperEquals, source); + statements.add(ifSuperEquals); + } + for (EclipseNode field : fields) { TypeReference fType = getFieldType(field, useFieldsDirectly); char[] token = fType.getLastToken(); Expression thisFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source); - Expression otherFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source, otherN); + Expression otherFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source, otherName); if (fType.dimensions() == 0 && token != null) { if (Arrays.equals(TypeConstants.FLOAT, token)) { @@ -589,7 +621,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA Eclipse.setGeneratedBy(equalsCall, source); equalsCall.receiver = createFieldAccessor(field, useFieldsDirectly, source); equalsCall.selector = "equals".toCharArray(); - equalsCall.arguments = new Expression[] { createFieldAccessor(field, useFieldsDirectly, source, otherN) }; + equalsCall.arguments = new Expression[] { createFieldAccessor(field, useFieldsDirectly, source, otherName) }; UnaryExpression fieldsNotEqual = new UnaryExpression(equalsCall, OperatorIds.NOT); fieldsNotEqual.sourceStart = pS; fieldsNotEqual.sourceEnd = pE; Eclipse.setGeneratedBy(fieldsNotEqual, source); @@ -639,6 +671,54 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA return method; } + + private MethodDeclaration createCanEqual(EclipseNode type, ASTNode source) { + /* public boolean canEquals(final java.lang.Object other) { + * return other instanceof MyType; + * } + */ + int pS = source.sourceStart; int pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + char[] otherName = "other".toCharArray(); + + MethodDeclaration method = new MethodDeclaration( + ((CompilationUnitDeclaration) type.top().get()).compilationResult); + Eclipse.setGeneratedBy(method, source); + method.modifiers = EclipseHandlerUtil.toEclipseModifier(AccessLevel.PUBLIC); + method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); + method.returnType.sourceStart = pS; method.returnType.sourceEnd = pE; + Eclipse.setGeneratedBy(method.returnType, source); + method.selector = "canEqual".toCharArray(); + method.thrownExceptions = null; + method.typeParameters = null; + method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart; + method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd; + TypeReference objectRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { p, p, p }); + Eclipse.setGeneratedBy(objectRef, source); + method.arguments = new Argument[] {new Argument(otherName, 0, objectRef, Modifier.FINAL)}; + method.arguments[0].sourceStart = pS; method.arguments[0].sourceEnd = pE; + Eclipse.setGeneratedBy(method.arguments[0], source); + + SingleNameReference otherRef = new SingleNameReference(otherName, p); + Eclipse.setGeneratedBy(otherRef, source); + + SingleTypeReference typeReference = new SingleTypeReference(((TypeDeclaration)type.get()).name, p); + Eclipse.setGeneratedBy(typeReference, source); + + InstanceOfExpression instanceOf = new InstanceOfExpression(otherRef, typeReference); + instanceOf.sourceStart = pS; instanceOf.sourceEnd = pE; + Eclipse.setGeneratedBy(instanceOf, source); + + ReturnStatement returnStatement = new ReturnStatement(instanceOf, pS, pE); + Eclipse.setGeneratedBy(returnStatement, source); + + method.statements = new Statement[] {returnStatement}; + return method; + } + + private IfStatement generateCompareFloatOrDouble(Expression thisRef, Expression otherRef, char[] floatOrDouble, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; /* if (Float.compare(fieldName, other.fieldName) != 0) return false */ diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java new file mode 100644 index 00000000..736e6e43 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -0,0 +1,284 @@ +/* + * Copyright © 2009 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.eclipse.handlers; + +import static lombok.eclipse.Eclipse.fromQualifiedName; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.lang.reflect.Modifier; +import java.util.Arrays; + +import lombok.core.AnnotationValues; +import lombok.eclipse.Eclipse; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.NameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.mangosdk.spi.ProviderFor; + +public class HandleLog { + + private HandleLog() { + throw new UnsupportedOperationException(); + } + + public static boolean processAnnotation(LoggingFramework framework, AnnotationValues<? extends java.lang.annotation.Annotation> annotation, Annotation source, EclipseNode annotationNode) { + Expression annotationValue = (Expression) annotation.getActualExpression("value"); + if (annotationValue != null && !(annotationValue instanceof ClassLiteralAccess)) { + return true; + } + ClassLiteralAccess loggingType = (ClassLiteralAccess)annotationValue; + + EclipseNode owner = annotationNode.up(); + switch (owner.getKind()) { + case TYPE: + TypeDeclaration typeDecl = null; + if (owner.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) owner.get(); + int modifiers = typeDecl == null ? 0 : typeDecl.modifiers; + + boolean notAClass = (modifiers & + (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; + + if (typeDecl == null || notAClass) { + annotationNode.addError("@Log is legal only on classes and enums."); + return false; + } + + if (fieldExists("log", owner) != MemberExistsResult.NOT_EXISTS) { + annotationNode.addWarning("Field 'log' already exists."); + return true; + } + + if (loggingType == null) { + loggingType = selfType(owner, source); + } + + injectField(owner, createField(framework, source, loggingType)); + owner.rebuild(); + return true; + default: + annotationNode.addError("@Log is legal only on types."); + return true; + } + } + + private static ClassLiteralAccess selfType(EclipseNode type, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + TypeDeclaration typeDeclaration = (TypeDeclaration)type.get(); + TypeReference typeReference = new SingleTypeReference(typeDeclaration.name, p); + Eclipse.setGeneratedBy(typeReference, source); + + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, typeReference); + Eclipse.setGeneratedBy(result, source); + + return result; + } + + private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + // private static final <loggerType> log = <factoryMethod>(<parameter>); + + FieldDeclaration fieldDecl = new FieldDeclaration("log".toCharArray(), 0, -1); + Eclipse.setGeneratedBy(fieldDecl, source); + fieldDecl.declarationSourceEnd = -1; + fieldDecl.modifiers = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; + + fieldDecl.type = createTypeReference(framework.getLoggerTypeName(), source); + + MessageSend factoryMethodCall = new MessageSend(); + Eclipse.setGeneratedBy(factoryMethodCall, source); + + factoryMethodCall.receiver = createNameReference(framework.getLoggerFactoryTypeName(), source); + factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray(); + + Expression parameter = framework.createFactoryParameter(loggingType, source); + + factoryMethodCall.arguments = new Expression[] { parameter }; + factoryMethodCall.nameSourcePosition = p; + factoryMethodCall.sourceStart = pS; + factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE; + + fieldDecl.initialization = factoryMethodCall; + + return fieldDecl; + } + + private static TypeReference createTypeReference(String typeName, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + TypeReference typeReference; + if (typeName.contains(".")) { + + char[][] typeNameTokens = fromQualifiedName(typeName); + long[] pos = new long[typeNameTokens.length]; + Arrays.fill(pos, p); + + typeReference = new QualifiedTypeReference(typeNameTokens, pos); + } + else { + typeReference = null; + } + + Eclipse.setGeneratedBy(typeReference, source); + return typeReference; + } + + private static NameReference createNameReference(String name, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + char[][] nameTokens = fromQualifiedName(name); + long[] pos = new long[nameTokens.length]; + Arrays.fill(pos, p); + + QualifiedNameReference nameReference = new QualifiedNameReference(nameTokens, pos, pS, pE); + nameReference.statementEnd = pE; + + Eclipse.setGeneratedBy(nameReference, source); + return nameReference; + } + + /** + * Handles the {@link lombok.extern.apachecommons.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleCommonsLog implements EclipseAnnotationHandler<lombok.extern.apachecommons.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.apachecommons.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.jul.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleJulLog implements EclipseAnnotationHandler<lombok.extern.jul.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.jul.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.log4j.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleLog4jLog implements EclipseAnnotationHandler<lombok.extern.log4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.log4j.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.slf4j.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleSlf4jLog implements EclipseAnnotationHandler<lombok.extern.slf4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.slf4j.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode); + } + } + + enum LoggingFramework { + // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); + COMMONS(lombok.extern.jul.Log.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory", "getLog"), + + // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); + JUL(lombok.extern.jul.Log.class, "java.util.logging.Logger", "java.util.logging.Logger", "getLogger") { + @Override public Expression createFactoryParameter(ClassLiteralAccess type, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + MessageSend factoryParameterCall = new MessageSend(); + Eclipse.setGeneratedBy(factoryParameterCall, source); + + factoryParameterCall.receiver = super.createFactoryParameter(type, source); + factoryParameterCall.selector = "getName".toCharArray(); + + factoryParameterCall.nameSourcePosition = p; + factoryParameterCall.sourceStart = pS; + factoryParameterCall.sourceEnd = factoryParameterCall.statementEnd = pE; + + return factoryParameterCall; + } + }, + + // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); + LOG4J(lombok.extern.jul.Log.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger", "getLogger"), + + // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); + SLF4J(lombok.extern.slf4j.Log.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory", "getLogger"), + + ; + + private final Class<? extends java.lang.annotation.Annotation> annotationClass; + private final String loggerTypeName; + private final String loggerFactoryTypeName; + private final String loggerFactoryMethodName; + + LoggingFramework(Class<? extends java.lang.annotation.Annotation> annotationClass, String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName) { + this.annotationClass = annotationClass; + this.loggerTypeName = loggerTypeName; + this.loggerFactoryTypeName = loggerFactoryTypeName; + this.loggerFactoryMethodName = loggerFactoryMethodName; + } + + final Class<? extends java.lang.annotation.Annotation> getAnnotationClass() { + return annotationClass; + } + + final String getLoggerTypeName() { + return loggerTypeName; + } + + final String getLoggerFactoryTypeName() { + return loggerFactoryTypeName; + } + + final String getLoggerFactoryMethodName() { + return loggerFactoryMethodName; + } + + Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source){ + TypeReference copy = Eclipse.copyType(loggingType.type, source); + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy); + Eclipse.setGeneratedBy(result, source); + return result; + }; + } +} diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index fde36192..b77099b5 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -101,7 +101,7 @@ public class HandleSynchronized implements EclipseAnnotationHandler<Synchronized fieldDecl.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { 0, 0, 0 }); Eclipse.setGeneratedBy(fieldDecl.type, source); fieldDecl.initialization = arrayAlloc; - injectField(annotationNode.up().up(), fieldDecl); + injectFieldSuppressWarnings(annotationNode.up().up(), fieldDecl); } if (method.statements == null) return false; diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java new file mode 100644 index 00000000..b3cfa879 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.eclipse.handlers; + +import lombok.eclipse.EclipseASTAdapter; +import lombok.eclipse.EclipseASTVisitor; +import lombok.eclipse.EclipseNode; + +import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; +import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.mangosdk.spi.ProviderFor; + +/* + * This class just handles 2 basic error cases. The real meat of eclipse 'val' support is in {@code EclipsePatcher}'s {@code patchHandleVal} method. + */ +@ProviderFor(EclipseASTVisitor.class) +public class HandleVal extends EclipseASTAdapter { + @Override public void visitLocal(EclipseNode localNode, LocalDeclaration local) { + if (local.type instanceof SingleTypeReference) { + char[] token = ((SingleTypeReference)local.type).token; + if (token == null || token.length != 3) return; + else if (token[0] != 'v' || token[1] != 'a' || token[2] != 'l') return; + + boolean variableOfForEach = false; + + if (localNode.directUp().get() instanceof ForeachStatement) { + ForeachStatement fs = (ForeachStatement) localNode.directUp().get(); + variableOfForEach = fs.elementVariable == local; + } + + if (local.initialization == null && !variableOfForEach) { + localNode.addError("'val' on a local variable requires an initializer expression"); + } + + if (local.initialization instanceof ArrayInitializer) { + localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + } + } + } +} diff --git a/src/core/lombok/extern/apachecommons/Log.java b/src/core/lombok/extern/apachecommons/Log.java new file mode 100644 index 00000000..4c82a2a7 --- /dev/null +++ b/src/core/lombok/extern/apachecommons/Log.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.extern.apachecommons; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(java.util.List.class); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.jul.Log lombok.extern.jul.Log + * @see lombok.extern.log4j.Log lombok.extern.log4j.Log + * @see lombok.extern.slf4j.Log lombok.extern.slf4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +}
\ No newline at end of file diff --git a/src/core/lombok/extern/jul/Log.java b/src/core/lombok/extern/jul/Log.java new file mode 100644 index 00000000..a66db671 --- /dev/null +++ b/src/core/lombok/extern/jul/Log.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.extern.jul; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName()); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(java.util.List.class.getName()); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.apachecommons.Log lombok.extern.apachecommons.Log + * @see lombok.extern.log4j.Log lombok.extern.log4j.Log + * @see lombok.extern.slf4j.Log lombok.extern.slf4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +}
\ No newline at end of file diff --git a/src/core/lombok/extern/log4j/Log.java b/src/core/lombok/extern/log4j/Log.java new file mode 100644 index 00000000..151b5e98 --- /dev/null +++ b/src/core/lombok/extern/log4j/Log.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.extern.log4j; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(java.util.List.class); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.apachecommons.Log lombok.extern.apachecommons.Log + * @see lombok.extern.jul.Log lombok.extern.jul.Log + * @see lombok.extern.slf4j.Log lombok.extern.slf4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +}
\ No newline at end of file diff --git a/src/core/lombok/extern/slf4j/Log.java b/src/core/lombok/extern/slf4j/Log.java new file mode 100644 index 00000000..5431847a --- /dev/null +++ b/src/core/lombok/extern/slf4j/Log.java @@ -0,0 +1,74 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.extern.slf4j; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +/** + * Causes lombok to generate a logger field. + * Example: + * <pre> + * @Log + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class); + * } + * </pre> + * + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class. + * Example: + * <pre> + * @Log(java.util.List.class) + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.util.List.class); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * + * @see lombok.extern.apachecommons.Log lombok.extern.apachecommons.Log + * @see lombok.extern.jul.Log lombok.extern.jul.Log + * @see lombok.extern.log4j.Log lombok.extern.log4j.Log + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + /** + * If you do not want to use the annotated class as the logger parameter, you can specify an alternate class here. + */ + Class<?> value() default void.class; +} diff --git a/src/core/lombok/javac/HandlerLibrary.java b/src/core/lombok/javac/HandlerLibrary.java index bbbdacd0..5b792874 100644 --- a/src/core/lombok/javac/HandlerLibrary.java +++ b/src/core/lombok/javac/HandlerLibrary.java @@ -183,7 +183,13 @@ public class HandlerLibrary { */ public void callASTVisitors(JavacAST ast) { for (JavacASTVisitor visitor : visitorHandlers) try { - ast.traverse(visitor); + if (!visitor.isResolutionBased()) ast.traverse(visitor); + } catch (Throwable t) { + javacError(String.format("Lombok visitor handler %s failed", visitor.getClass()), t); + } + + for (JavacASTVisitor visitor : visitorHandlers) try { + if (visitor.isResolutionBased()) ast.traverse(visitor); } catch (Throwable t) { javacError(String.format("Lombok visitor handler %s failed", visitor.getClass()), t); } diff --git a/src/core/lombok/javac/Javac.java b/src/core/lombok/javac/Javac.java index 58a24207..6d9800ab 100644 --- a/src/core/lombok/javac/Javac.java +++ b/src/core/lombok/javac/Javac.java @@ -90,6 +90,7 @@ public class Javac { String name = m.getName(); List<String> raws = new ArrayList<String>(); List<Object> guesses = new ArrayList<Object>(); + List<Object> expressions = new ArrayList<Object>(); final List<DiagnosticPosition> positions = new ArrayList<DiagnosticPosition>(); boolean isExplicit = false; @@ -112,17 +113,19 @@ public class Javac { List<JCExpression> elems = ((JCNewArray)rhs).elems; for (JCExpression inner : elems) { raws.add(inner.toString()); + expressions.add(inner); guesses.add(calculateGuess(inner)); positions.add(inner.pos()); } } else { raws.add(rhs.toString()); + expressions.add(rhs); guesses.add(calculateGuess(rhs)); positions.add(rhs.pos()); } } - values.put(name, new AnnotationValue(node, raws, guesses, isExplicit) { + values.put(name, new AnnotationValue(node, raws, expressions, guesses, isExplicit) { @Override public void setError(String message, int valueIdx) { if (valueIdx < 0) node.addError(message); else node.addError(message, positions.get(valueIdx)); diff --git a/src/core/lombok/javac/JavacASTAdapter.java b/src/core/lombok/javac/JavacASTAdapter.java index 41bc46d3..bbdb6876 100644 --- a/src/core/lombok/javac/JavacASTAdapter.java +++ b/src/core/lombok/javac/JavacASTAdapter.java @@ -35,6 +35,11 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; */ public class JavacASTAdapter implements JavacASTVisitor { /** {@inheritDoc} */ + @Override public boolean isResolutionBased() { + return false; + } + + /** {@inheritDoc} */ @Override public void visitCompilationUnit(JavacNode top, JCCompilationUnit unit) {} /** {@inheritDoc} */ diff --git a/src/core/lombok/javac/JavacASTVisitor.java b/src/core/lombok/javac/JavacASTVisitor.java index 3c5887a7..18376037 100644 --- a/src/core/lombok/javac/JavacASTVisitor.java +++ b/src/core/lombok/javac/JavacASTVisitor.java @@ -38,6 +38,12 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; */ public interface JavacASTVisitor { /** + * If true, you'll be called after all the non-resolution based visitors. + * NB: Temporary solution - will be rewritten to a different style altogether in a future release. + */ + boolean isResolutionBased(); + + /** * Called at the very beginning and end. */ void visitCompilationUnit(JavacNode top, JCCompilationUnit unit); @@ -101,6 +107,10 @@ public interface JavacASTVisitor { private int disablePrinting = 0; private int indent = 0; + @Override public boolean isResolutionBased() { + return false; + } + /** * @param printContent if true, bodies are printed directly, as java code, * instead of a tree listing of every AST node inside it. diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java new file mode 100644 index 00000000..e0eb436d --- /dev/null +++ b/src/core/lombok/javac/JavacResolution.java @@ -0,0 +1,414 @@ +package lombok.javac; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.util.ArrayDeque; +import java.util.Map; + +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; +import com.sun.tools.javac.code.Symtab; +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; +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; +import com.sun.tools.javac.comp.Enter; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.comp.MemberEnter; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCBlock; +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.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.Log; + +public class JavacResolution { + private final Attr attr; + private final LogDisabler logDisabler; + + 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 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; + + static { + boolean z; + Field a = null, b = null, c = null, d = null, e = null, f = 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 (Exception x) { + z = true; + } + + errWriterField = a; + warnWriterField = b; + noticeWriterField = c; + dumpOnErrorField = d; + promptOnErrorField = e; + diagnosticListenerField = f; + 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 (!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) {} + } + } + + private static final class EnvFinder extends JCTree.Visitor { + private Env<AttrContext> env = null; + private Enter enter; + private MemberEnter memberEnter; + private JCTree copyAt = null; + + EnvFinder(Context context) { + this.enter = Enter.instance(context); + this.memberEnter = MemberEnter.instance(context); + } + + Env<AttrContext> get() { + return env; + } + + JCTree copyAt() { + return copyAt; + } + + @Override public void visitTopLevel(JCCompilationUnit tree) { + if (copyAt != null) return; + env = enter.getTopLevelEnv(tree); + } + + @Override public void visitClassDef(JCClassDecl tree) { + if (copyAt != null) return; + // The commented out one leaves the 'lint' field unset, which causes NPEs during attrib. So, we use the other one. + //env = enter.classEnv((JCClassDecl) tree, env); + env = enter.getClassEnv(tree.sym); + } + + @Override public void visitMethodDef(JCMethodDecl tree) { + if (copyAt != null) return; + env = memberEnter.getMethodEnv(tree, env); + copyAt = tree; + } + + public void visitVarDef(JCVariableDecl tree) { + if (copyAt != null) return; + env = memberEnter.getInitEnv(tree, env); + copyAt = tree; + } + + @Override public void visitBlock(JCBlock tree) { + if (copyAt != null) return; + copyAt = tree; + } + + @Override public void visitTree(JCTree that) { + } + } + + public Map<JCTree, JCTree> resolve(JavacNode node) { + ArrayDeque<JCTree> stack = new ArrayDeque<JCTree>(); + + { + JavacNode n = node; + while (n != null) { + stack.push(n.get()); + n = n.up(); + } + } + + logDisabler.disableLoggers(); + try { + EnvFinder finder = new EnvFinder(node.getContext()); + while (!stack.isEmpty()) stack.pop().accept(finder); + + TreeMirrorMaker mirrorMaker = new TreeMirrorMaker(node); + JCTree copy = mirrorMaker.copy(finder.copyAt()); + + attrib(copy, finder.get()); + return mirrorMaker.getOriginalToCopyMap(); + } finally { + logDisabler.enableLoggers(); + } + } + + private void attrib(JCTree tree, Env<AttrContext> env) { + if (tree instanceof JCBlock) attr.attribStat(tree, env); + else if (tree instanceof JCMethodDecl) attr.attribStat(((JCMethodDecl)tree).body, env); + else if (tree instanceof JCVariableDecl) attr.attribStat(tree, env); + else throw new IllegalStateException("Called with something that isn't a block, method decl, or variable decl"); + } + + public static class TypeNotConvertibleException extends Exception { + public TypeNotConvertibleException(String msg) { + super(msg); + } + } + + public static Type ifTypeIsIterableToComponent(Type type, JavacAST ast) { + Types types = Types.instance(ast.getContext()); + Symtab syms = Symtab.instance(ast.getContext()); + Type boundType = types.upperBound(type); + Type elemTypeIfArray = types.elemtype(boundType); + if (elemTypeIfArray != null) return elemTypeIfArray; + + Type base = types.asSuper(boundType, syms.iterableType.tsym); + if (base == null) return syms.objectType; + + List<Type> iterableParams = base.allparams(); + return iterableParams.isEmpty() ? syms.objectType : types.upperBound(iterableParams.head); + } + + public static JCExpression typeToJCTree(Type type, TreeMaker maker, JavacAST ast) throws TypeNotConvertibleException { + return typeToJCTree(type, maker, ast, false); + } + + public static JCExpression createJavaLangObject(TreeMaker maker, JavacAST ast) { + JCExpression out = maker.Ident(ast.toName("java")); + out = maker.Select(out, ast.toName("lang")); + out = maker.Select(out, ast.toName("Object")); + return out; + } + + private static JCExpression typeToJCTree(Type type, TreeMaker maker, JavacAST ast, boolean allowCompound) throws TypeNotConvertibleException { + int dims = 0; + Type type0 = type; + while (type0 instanceof ArrayType) { + dims++; + type0 = ((ArrayType)type0).elemtype; + } + + JCExpression result = typeToJCTree0(type0, maker, ast, allowCompound); + while (dims > 0) { + result = maker.TypeArray(result); + dims--; + } + return result; + } + + private static JCExpression typeToJCTree0(Type type, TreeMaker maker, JavacAST ast, boolean allowCompound) throws TypeNotConvertibleException { + // 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. + + if (type.isPrimitive()) return primitiveToJCTree(type.getKind(), maker); + if (type.isErroneous()) throw new TypeNotConvertibleException("Type cannot be resolved"); + + TypeSymbol symbol = type.asElement(); + List<Type> generics = type.getTypeArguments(); + + JCExpression replacement = null; + + if (symbol == null) throw new TypeNotConvertibleException("Null or compound type"); + + if (symbol.name.len == 0) { + // Anonymous inner class + if (type instanceof ClassType) { + List<Type> ifaces = ((ClassType)type).interfaces_field; + Type supertype = ((ClassType)type).supertype_field; + if (ifaces != null && ifaces.length() == 1) { + return typeToJCTree(ifaces.get(0), maker, ast, allowCompound); + } + if (supertype != null) return typeToJCTree(supertype, maker, ast, allowCompound); + } + throw new TypeNotConvertibleException("Anonymous inner class"); + } + + if (type instanceof CapturedType) { + if (allowCompound) { + if (type.getLowerBound() == null || type.getLowerBound().tag == TypeTags.BOT) { + if (type.getUpperBound().toString().equals("java.lang.Object")) { + return maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); + } + return maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), typeToJCTree(type.getUpperBound(), maker, ast, false)); + } else { + return maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), typeToJCTree(type.getLowerBound(), maker, ast, false)); + } + } + if (type.getUpperBound() != null) { + return typeToJCTree(type.getUpperBound(), maker, ast, allowCompound); + } + + return createJavaLangObject(maker, ast); + } + + String qName = symbol.getQualifiedName().toString(); + if (qName.isEmpty()) throw new TypeNotConvertibleException("unknown type"); + if (qName.startsWith("<")) throw new TypeNotConvertibleException(qName); + String[] baseNames = symbol.getQualifiedName().toString().split("\\."); + replacement = maker.Ident(ast.toName(baseNames[0])); + for (int i = 1; i < baseNames.length; i++) { + replacement = maker.Select(replacement, ast.toName(baseNames[i])); + } + + if (generics != null && !generics.isEmpty()) { + List<JCExpression> args = List.nil(); + for (Type t : generics) args = args.append(typeToJCTree(t, maker, ast, true)); + replacement = maker.TypeApply(replacement, args); + } + + return replacement; + } + + private static JCExpression primitiveToJCTree(TypeKind kind, TreeMaker maker) throws TypeNotConvertibleException { + switch (kind) { + case BYTE: + return maker.TypeIdent(TypeTags.BYTE); + case CHAR: + return maker.TypeIdent(TypeTags.CHAR); + case SHORT: + return maker.TypeIdent(TypeTags.SHORT); + case INT: + return maker.TypeIdent(TypeTags.INT); + case LONG: + return maker.TypeIdent(TypeTags.LONG); + case FLOAT: + return maker.TypeIdent(TypeTags.FLOAT); + case DOUBLE: + return maker.TypeIdent(TypeTags.DOUBLE); + case BOOLEAN: + return maker.TypeIdent(TypeTags.BOOLEAN); + case VOID: + return maker.TypeIdent(TypeTags.VOID); + case NULL: + case NONE: + case OTHER: + default: + throw new TypeNotConvertibleException("Nulltype"); + } + } +} diff --git a/src/core/lombok/javac/TreeMirrorMaker.java b/src/core/lombok/javac/TreeMirrorMaker.java new file mode 100644 index 00000000..1c0b9311 --- /dev/null +++ b/src/core/lombok/javac/TreeMirrorMaker.java @@ -0,0 +1,50 @@ +package lombok.javac; + +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.Map; + +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeCopier; +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(JavacNode node) { + super(node.getTreeMaker()); + } + + @Override public <T extends JCTree> T copy(T original) { + T copy = super.copy(original); + originalToCopy.put(original, copy); + return copy; + } + + @Override public <T extends JCTree> T copy(T original, Void p) { + T copy = super.copy(original, p); + originalToCopy.put(original, copy); + return copy; + } + + @Override public <T extends JCTree> List<T> copy(List<T> originals) { + List<T> copies = super.copy(originals); + Iterator<T> it1 = originals.iterator(); + Iterator<T> it2 = copies.iterator(); + while (it1.hasNext()) originalToCopy.put(it1.next(), it2.next()); + return copies; + } + + @Override public <T extends JCTree> List<T> copy(List<T> originals, Void p) { + List<T> copies = super.copy(originals, p); + Iterator<T> it1 = originals.iterator(); + Iterator<T> it2 = copies.iterator(); + while (it1.hasNext()) originalToCopy.put(it1.next(), it2.next()); + return copies; + } + + public Map<JCTree, JCTree> getOriginalToCopyMap() { + return Collections.unmodifiableMap(originalToCopy); + } +} diff --git a/src/core/lombok/javac/apt/Processor.java b/src/core/lombok/javac/apt/Processor.java index 1d3d0c34..037f5ba5 100644 --- a/src/core/lombok/javac/apt/Processor.java +++ b/src/core/lombok/javac/apt/Processor.java @@ -157,6 +157,8 @@ public class Processor extends AbstractProcessor { ClassLoader unwrapped = (ClassLoader) f.get(processingEnv); ClassLoader wrapped = new WrappingClassLoader(unwrapped); f.set(processingEnv, wrapped); + } catch (NoSuchFieldException e) { + // Some versions of javac have this (and call close on it), some don't. I guess this one doesn't have it. } catch (Throwable t) { throw Lombok.sneakyThrow(t); } diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java index 2c89d9ad..779dd3ea 100644 --- a/src/core/lombok/javac/handlers/HandleCleanup.java +++ b/src/core/lombok/javac/handlers/HandleCleanup.java @@ -30,10 +30,12 @@ import lombok.javac.JavacNode; 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.TreeMaker; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCBinary; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCCatch; @@ -41,6 +43,7 @@ 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.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCIf; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeCast; @@ -108,11 +111,16 @@ public class HandleCleanup implements JavacAnnotationHandler<Cleanup> { doAssignmentCheck(annotationNode, tryBlock, decl.name); TreeMaker maker = annotationNode.getTreeMaker(); - JCFieldAccess cleanupCall = maker.Select(maker.Ident(decl.name), annotationNode.toName(cleanupName)); - List<JCStatement> finalizerBlock = List.<JCStatement>of(maker.Exec( - maker.Apply(List.<JCExpression>nil(), cleanupCall, List.<JCExpression>nil()))); + 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()))); + + JCBinary isNull = maker.Binary(JCTree.NE, maker.Ident(decl.name), maker.Literal(TypeTags.BOT, null)); + + JCIf ifNotNullCleanup = maker.If(isNull, maker.Block(0, cleanupCall), null); + + JCBlock finalizer = maker.Block(0, List.<JCStatement>of(ifNotNullCleanup)); - JCBlock finalizer = maker.Block(0, finalizerBlock); newStatements = newStatements.append(maker.Try(maker.Block(0, tryBlock), List.<JCCatch>nil(), finalizer)); if (blockNode instanceof JCBlock) { diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index ee049f1f..c5475fb1 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -167,9 +167,13 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd } } + boolean needsCanEqual = false; switch (methodExists("equals", typeNode)) { case NOT_EXISTS: - JCMethodDecl method = createEquals(typeNode, nodesForEquality, callSuper, useFieldsDirectly); + boolean isFinal = (((JCClassDecl)typeNode.get()).mods.flags & Flags.FINAL) != 0; + needsCanEqual = !isFinal || !isDirectDescendantOfObject; + + JCMethodDecl method = createEquals(typeNode, nodesForEquality, callSuper, useFieldsDirectly, needsCanEqual); injectMethod(typeNode, method); break; case EXISTS_BY_LOMBOK: @@ -182,6 +186,18 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd break; } + if (needsCanEqual) { + switch (methodExists("canEqual", typeNode)) { + case NOT_EXISTS: + JCMethodDecl method = createCanEqual(typeNode); + injectMethod(typeNode, method); + break; + case EXISTS_BY_LOMBOK: + case EXISTS_BY_USER: + default: + break; + } + } switch (methodExists("hashCode", typeNode)) { case NOT_EXISTS: JCMethodDecl method = createHashCode(typeNode, nodesForEquality, callSuper, useFieldsDirectly); @@ -196,7 +212,6 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd } break; } - return true; } @@ -314,7 +329,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd return maker.TypeCast(maker.TypeIdent(TypeTags.INT), xorBits); } - private JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, boolean useFieldsDirectly) { + private JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, boolean useFieldsDirectly, boolean needsCanEqual) { TreeMaker maker = typeNode.getTreeMaker(); JCClassDecl type = (JCClassDecl) typeNode.get(); @@ -335,27 +350,9 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd maker.Ident(thisName)), returnBool(maker, true), null)); } - /* if (o == null) return false; */ { - statements = statements.append(maker.If(maker.Binary(JCTree.EQ, maker.Ident(oName), - maker.Literal(TypeTags.BOT, null)), returnBool(maker, false), null)); - } - - /* if (o.getClass() != this.getClass()) return false; */ { - Name getClass = typeNode.toName("getClass"); - List<JCExpression> exprNil = List.nil(); - JCExpression oGetClass = maker.Apply(exprNil, maker.Select(maker.Ident(oName), getClass), exprNil); - JCExpression thisGetClass = maker.Apply(exprNil, maker.Select(maker.Ident(thisName), getClass), exprNil); - statements = statements.append( - maker.If(maker.Binary(JCTree.NE, oGetClass, thisGetClass), returnBool(maker, false), null)); - } - - /* if (!super.equals(o)) return false; */ - if (callSuper) { - JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(), - maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")), - List.<JCExpression>of(maker.Ident(oName))); - JCUnary superNotEqual = maker.Unary(JCTree.NOT, callToSuper); - statements = statements.append(maker.If(superNotEqual, returnBool(maker, false), null)); + /* if (!(o instanceof MyType) return false; */ { + JCUnary notInstanceOf = maker.Unary(JCTree.NOT, maker.TypeTest(maker.Ident(oName), maker.Ident(type.name))); + statements = statements.append(maker.If(notInstanceOf, returnBool(maker, false), null)); } /* MyType<?> other = (MyType<?>) o; */ { @@ -379,6 +376,25 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd maker.VarDef(maker.Modifiers(Flags.FINAL), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName)))); } + /* if (!other.canEqual(this)) return false; */ { + if (needsCanEqual) { + List<JCExpression> exprNil = List.nil(); + JCExpression equalityCheck = maker.Apply(exprNil, + maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")), + List.<JCExpression>of(maker.Ident(thisName))); + statements = statements.append(maker.If(maker.Unary(JCTree.NOT, equalityCheck), returnBool(maker, false), null)); + } + } + + /* if (!super.equals(o)) return false; */ + if (callSuper) { + JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(), + maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")), + List.<JCExpression>of(maker.Ident(oName))); + JCUnary superNotEqual = maker.Unary(JCTree.NOT, callToSuper); + statements = statements.append(maker.If(superNotEqual, returnBool(maker, false), null)); + } + for (JavacNode fieldNode : fields) { JCExpression fType = getFieldType(fieldNode, useFieldsDirectly); JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, useFieldsDirectly); @@ -428,6 +444,27 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd JCBlock body = maker.Block(0, statements); return maker.MethodDef(mods, typeNode.toName("equals"), returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null); } + + private JCMethodDecl createCanEqual(JavacNode typeNode) { + /* public boolean canEquals(final java.lang.Object other) { + * return other instanceof MyType; + * } + */ + TreeMaker maker = typeNode.getTreeMaker(); + JCClassDecl type = (JCClassDecl) typeNode.get(); + + JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.<JCAnnotation>nil()); + JCExpression returnType = maker.TypeIdent(TypeTags.BOOLEAN); + Name canEqualName = typeNode.toName("canEqual"); + JCExpression objectType = chainDots(maker, typeNode, "java", "lang", "Object"); + Name otherName = typeNode.toName("other"); + List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(Flags.FINAL), otherName, objectType, null)); + + JCBlock body = maker.Block(0, List.<JCStatement>of( + maker.Return(maker.TypeTest(maker.Ident(otherName), maker.Ident(type.name))))); + + return maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null); + } private JCStatement generateCompareFloatOrDouble(JCExpression thisDotField, JCExpression otherDotField, TreeMaker maker, JavacNode node, boolean isDouble) { @@ -442,5 +479,4 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd private JCStatement returnBool(TreeMaker maker, boolean bool) { return maker.Return(maker.Literal(TypeTags.BOOLEAN, bool ? 1 : 0)); } - } diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java new file mode 100644 index 00000000..03e40d7f --- /dev/null +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -0,0 +1,203 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.handlers; + +import static lombok.javac.handlers.JavacHandlerUtil.*; + +import java.lang.annotation.Annotation; + +import lombok.core.AnnotationValues; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; + +import org.mangosdk.spi.ProviderFor; + +import com.sun.tools.javac.code.Flags; +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; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; + +public class HandleLog { + + private HandleLog() { + throw new UnsupportedOperationException(); + } + + public static boolean processAnnotation(LoggingFramework framework, AnnotationValues<?> annotation, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, framework.getAnnotationClass()); + +// String loggingClassName = annotation.getRawExpression("value"); +// if (loggingClassName == null) loggingClassName = "void"; +// if (loggingClassName.endsWith(".class")) loggingClassName = loggingClassName.substring(0, loggingClassName.length() - 6); + + JCExpression annotationValue = (JCExpression) annotation.getActualExpression("value"); + JCFieldAccess loggingType = null; + if (annotationValue != null) { + if (!(annotationValue instanceof JCFieldAccess)) return true; + loggingType = (JCFieldAccess) annotationValue; + if (!loggingType.name.contentEquals("class")) return true; + } + + + JavacNode typeNode = annotationNode.up(); + switch (typeNode.getKind()) { + case TYPE: + if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE)!= 0) { + annotationNode.addError("@Log is legal only on classes and enums."); + return true; + } + + if (fieldExists("log", typeNode)!= MemberExistsResult.NOT_EXISTS) { + annotationNode.addWarning("Field 'log' already exists."); + return true; + } + + if (loggingType == null) { + loggingType = selfType(typeNode); + } + createField(framework, typeNode, loggingType); + return true; + default: + annotationNode.addError("@Log is legal only on types."); + return true; + } + } + + private static JCFieldAccess selfType(JavacNode typeNode) { + TreeMaker 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) { + TreeMaker maker = typeNode.getTreeMaker(); + + // private static final <loggerType> log = <factoryMethod>(<parameter>); + JCExpression loggerType = chainDotsString(maker, typeNode, framework.getLoggerTypeName()); + JCExpression factoryMethod = chainDotsString(maker, typeNode, framework.getLoggerFactoryMethodName()); + + JCExpression loggerName = framework.createFactoryParameter(typeNode, loggingType); + JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName)); + + JCVariableDecl fieldDecl = maker.VarDef( + maker.Modifiers(Flags.PRIVATE | Flags.FINAL | Flags.STATIC), + typeNode.toName("log"), loggerType, factoryMethodCall); + + injectField(typeNode, fieldDecl); + return true; + } + + /** + * Handles the {@link lombok.extern.apachecommons.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleCommonsLog implements JavacAnnotationHandler<lombok.extern.apachecommons.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.apachecommons.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.COMMONS, annotation, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.jul.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleJulLog implements JavacAnnotationHandler<lombok.extern.jul.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.jul.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.JUL, annotation, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.log4j.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleLog4jLog implements JavacAnnotationHandler<lombok.extern.log4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.log4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.LOG4J, annotation, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.slf4j.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleSlf4jLog implements JavacAnnotationHandler<lombok.extern.slf4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.slf4j.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LoggingFramework.SLF4J, annotation, annotationNode); + } + } + + enum LoggingFramework { + // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); + COMMONS(lombok.extern.jul.Log.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory.getLog"), + + // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); + JUL(lombok.extern.jul.Log.class, "java.util.logging.Logger", "java.util.logging.Logger.getLogger") { + @Override public JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { + TreeMaker maker = typeNode.getTreeMaker(); + JCExpression method = maker.Select(loggingType, typeNode.toName("getName")); + return maker.Apply(List.<JCExpression>nil(), method, List.<JCExpression>nil()); + } + }, + + // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); + LOG4J(lombok.extern.jul.Log.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger.getLogger"), + + // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); + SLF4J(lombok.extern.slf4j.Log.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory.getLogger"), + + ; + + private final Class<? extends Annotation> annotationClass; + private final String loggerTypeName; + private final String loggerFactoryName; + + LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName) { + this.annotationClass = annotationClass; + this.loggerTypeName = loggerTypeName; + this.loggerFactoryName = loggerFactoryName; + } + + final Class<? extends Annotation> getAnnotationClass() { + return annotationClass; + } + + final String getLoggerTypeName() { + return loggerTypeName; + } + + final String getLoggerFactoryMethodName() { + return loggerFactoryName; + } + + JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { + return loggingType; + } + } +} diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java index 2f900eb8..a095aaf1 100644 --- a/src/core/lombok/javac/handlers/HandleSynchronized.java +++ b/src/core/lombok/javac/handlers/HandleSynchronized.java @@ -89,7 +89,7 @@ public class HandleSynchronized implements JavacAnnotationHandler<Synchronized> JCVariableDecl fieldDecl = maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (isStatic ? Flags.STATIC : 0)), methodNode.toName(lockName), objectType, newObjectArray); - injectField(methodNode.up(), fieldDecl); + injectFieldSuppressWarnings(methodNode.up(), fieldDecl); } if (method.body == null) return false; diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java new file mode 100644 index 00000000..5da6fec0 --- /dev/null +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -0,0 +1,113 @@ +/* + * Copyright © 2010 Reinier Zwitserloot and Roel Spilker. + * + * 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.handlers; + +import lombok.javac.JavacASTAdapter; +import lombok.javac.JavacASTVisitor; +import lombok.javac.JavacNode; +import lombok.javac.JavacResolution; + +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.JCEnhancedForLoop; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; + +@ProviderFor(JavacASTVisitor.class) +public class HandleVal extends JavacASTAdapter { + @Override public boolean isResolutionBased() { + return true; + } + + @Override public void visitLocal(JavacNode localNode, JCVariableDecl local) { + if (local.vartype != null && local.vartype.toString().equals("val")) { + JCExpression rhsOfEnhancedForLoop = null; + if (local.init == null) { + JCTree parentRaw = localNode.directUp().get(); + if (parentRaw instanceof JCEnhancedForLoop) { + JCEnhancedForLoop efl = (JCEnhancedForLoop) parentRaw; + if (efl.var == local) rhsOfEnhancedForLoop = efl.expr; + } + } + + if (rhsOfEnhancedForLoop == null && local.init == null) { + localNode.addError("'val' on a local variable requires an initializer expression"); + return; + } + + if (local.init instanceof JCNewArray && ((JCNewArray)local.init).elemtype == null) { + localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + return; + } + + local.mods.flags |= Flags.FINAL; + local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst()); + + Type type; + try { + if (rhsOfEnhancedForLoop == null) { + if (local.init.type == null) { + JavacResolution resolver = new JavacResolution(localNode.getContext()); + type = ((JCExpression) resolver.resolve(localNode).get(local.init)).type; + } else { + type = local.init.type; + } + } else { + if (rhsOfEnhancedForLoop.type == null) { + JavacResolution resolver = new JavacResolution(localNode.getContext()); + type = ((JCExpression) resolver.resolve(localNode.directUp()).get(rhsOfEnhancedForLoop)).type; + } else { + type = rhsOfEnhancedForLoop.type; + } + } + + try { + JCExpression replacement; + + if (rhsOfEnhancedForLoop != null) { + Type componentType = JavacResolution.ifTypeIsIterableToComponent(type, localNode.getAst()); + if (componentType == null) replacement = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst()); + else replacement = JavacResolution.typeToJCTree(componentType, localNode.getTreeMaker(), localNode.getAst()); + } else { + replacement = JavacResolution.typeToJCTree(type, localNode.getTreeMaker(), localNode.getAst()); + } + + if (replacement != null) { + local.vartype = replacement; + localNode.getAst().setChanged(); + } + else local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());; + } catch (JavacResolution.TypeNotConvertibleException e) { + localNode.addError("Cannot use 'val' here because initializer expression does not have a representable type: " + e.getMessage()); + local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());; + } + } catch (RuntimeException e) { + local.vartype = JavacResolution.createJavaLangObject(localNode.getTreeMaker(), localNode.getAst());; + throw e; + } + } + } +} diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 79436327..5dacf2ca 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -392,13 +392,26 @@ public class JavacHandlerUtil { /** * Adds the given new field declaration to the provided type AST Node. + * The field carries the @{@link SuppressWarnings}("all") annotation. + * Also takes care of updating the JavacAST. + */ + public static void injectFieldSuppressWarnings(JavacNode typeNode, JCVariableDecl field) { + injectField(typeNode, field, true); + } + + /** + * Adds the given new field declaration to the provided type AST Node. * * Also takes care of updating the JavacAST. */ public static void injectField(JavacNode typeNode, JCVariableDecl field) { + injectField(typeNode, field, false); + } + + private static void injectField(JavacNode typeNode, JCVariableDecl field, boolean addSuppressWarnings) { JCClassDecl type = (JCClassDecl) typeNode.get(); - addSuppressWarningsAll(field.mods, typeNode, field.pos); + if (addSuppressWarnings) addSuppressWarningsAll(field.mods, typeNode, field.pos); type.defs = type.defs.append(field); typeNode.add(field, Kind.FIELD).recursiveSetHandled(); @@ -476,6 +489,21 @@ public class JavacHandlerUtil { return e; } + + + /** + * In javac, dotted access of any kind, from {@code java.lang.String} to {@code var.methodName} + * is represented by a fold-left of {@code Select} nodes with the leftmost string represented by + * a {@code Ident} node. This method generates such an expression. + * + * For example, maker.Select(maker.Select(maker.Ident(NAME[java]), NAME[lang]), NAME[String]). + * + * @see com.sun.tools.javac.tree.JCTree.JCIdent + * @see com.sun.tools.javac.tree.JCTree.JCFieldAccess + */ + public static JCExpression chainDotsString(TreeMaker maker, JavacNode node, String elems) { + return chainDots(maker, node, elems.split("\\.")); + } /** * Searches the given field node for annotations and returns each one that matches the provided regular expression pattern. diff --git a/src/delombok/lombok/delombok/CommentCollectingScanner.java b/src/delombok/lombok/delombok/CommentCollectingScanner.java index 2552cbf7..c930bc62 100644 --- a/src/delombok/lombok/delombok/CommentCollectingScanner.java +++ b/src/delombok/lombok/delombok/CommentCollectingScanner.java @@ -25,7 +25,7 @@ import java.nio.CharBuffer; import lombok.delombok.Comment.EndConnection; import lombok.delombok.Comment.StartConnection; -import lombok.delombok.CommentPreservingParser.Comments; +import lombok.delombok.Delombok.Comments; import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.util.Context; diff --git a/src/delombok/lombok/delombok/CommentPreservingParser.java b/src/delombok/lombok/delombok/CommentPreservingParser.java deleted file mode 100644 index 87c02dcd..00000000 --- a/src/delombok/lombok/delombok/CommentPreservingParser.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. - * - * 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 java.io.IOException; -import java.io.Writer; -import java.util.Collections; -import java.util.Date; - -import javax.annotation.processing.Messager; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.tools.DiagnosticListener; -import javax.tools.JavaFileObject; -import javax.tools.Diagnostic.Kind; - -import lombok.javac.DeleteLombokAnnotations; -import lombok.javac.JavacTransformer; - -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.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Options; - -public class CommentPreservingParser { - private final String encoding; - private boolean deleteLombokAnnotations = false; - private DiagnosticListener<JavaFileObject> diagnostics = null; - - public CommentPreservingParser() { - this("utf-8"); - } - - public CommentPreservingParser(String encoding) { - this.encoding = encoding; - } - - public void setDeleteLombokAnnotations(boolean deleteLombokAnnotations) { - this.deleteLombokAnnotations = deleteLombokAnnotations; - } - - public void setDiagnosticsListener(DiagnosticListener<JavaFileObject> diagnostics) { - this.diagnostics = diagnostics; - } - - public ParseResult parse(JavaFileObject source, boolean forceProcessing) throws IOException { - return doParse(source, forceProcessing); - } - - public ParseResult parse(String fileName, boolean forceProcessing) throws IOException { - return doParse(fileName, forceProcessing); - } - - private ParseResult doParse(Object source, boolean forceProcessing) throws IOException { - Context context = new Context(); - - Options.instance(context).put(OptionName.ENCODING, encoding); - - if (diagnostics != null) context.put(DiagnosticListener.class, diagnostics); - - CommentCollectingScanner.Factory.preRegister(context); - - JavaCompiler compiler = new JavaCompiler(context) { - @Override - protected boolean keepComments() { - return true; - } - }; - - compiler.genEndPos = true; - - Comments comments = new Comments(); - context.put(Comments.class, comments); - if (deleteLombokAnnotations) context.put(DeleteLombokAnnotations.class, new DeleteLombokAnnotations(true)); - - comments.comments = List.nil(); - - JCCompilationUnit cu; - if (source instanceof JavaFileObject) { - cu = compiler.parse((JavaFileObject) source); - } else { - @SuppressWarnings("deprecation") - JCCompilationUnit unit = compiler.parse((String)source); - cu = unit; - } - - boolean changed = new JavacTransformer(messager).transform(context, Collections.singleton(cu)); - return new ParseResult(comments.comments, cu, forceProcessing || changed); - } - - private static final Messager messager = new Messager() { - @Override public void printMessage(Kind kind, CharSequence msg) { - System.out.printf("%s: %s\n", kind, msg); - } - - @Override public void printMessage(Kind kind, CharSequence msg, Element e) { - System.out.printf("%s: %s\n", kind, msg); - } - - @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) { - System.out.printf("%s: %s\n", kind, msg); - } - - @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) { - System.out.printf("%s: %s\n", kind, msg); - } - }; - - static class Comments { - List<Comment> comments = List.nil(); - - void add(Comment comment) { - comments = comments.append(comment); - } - } - - public static class ParseResult { - private final List<Comment> comments; - private final JCCompilationUnit compilationUnit; - private final boolean changed; - - private ParseResult(List<Comment> comments, JCCompilationUnit compilationUnit, boolean changed) { - this.comments = comments; - this.compilationUnit = compilationUnit; - this.changed = changed; - } - - public void print(Writer out) throws IOException { - if (!changed) { - JavaFileObject sourceFile = compilationUnit.getSourceFile(); - if (sourceFile != null) { - out.write(sourceFile.getCharContent(true).toString()); - return; - } - } - - out.write("// Generated by delombok at "); - out.write(String.valueOf(new Date())); - out.write(System.getProperty("line.separator")); - - compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments)); - } - - public boolean isChanged() { - return changed; - } - } -} diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 56994f78..6866d97f 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -30,16 +30,33 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.Writer; +import java.net.URI; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import javax.annotation.processing.Messager; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; +import javax.tools.Diagnostic.Kind; -import lombok.delombok.CommentPreservingParser.ParseResult; +import lombok.javac.DeleteLombokAnnotations; +import lombok.javac.JavacTransformer; +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.sun.tools.javac.util.Options; import com.zwitserloot.cmdreader.CmdReader; import com.zwitserloot.cmdreader.Description; import com.zwitserloot.cmdreader.Excludes; @@ -50,16 +67,24 @@ import com.zwitserloot.cmdreader.Shorthand; public class Delombok { private Charset charset = Charset.defaultCharset(); - private CommentPreservingParser parser = new CommentPreservingParser(); + private Context context = new Context(); + private Writer presetWriter; - { - parser.setDeleteLombokAnnotations(true); + public void setWriter(Writer writer) { + this.presetWriter = writer; + } + + public Delombok() { + context.put(DeleteLombokAnnotations.class, new DeleteLombokAnnotations(true)); } private PrintStream feedback = System.err; private boolean verbose; private boolean noCopy; private boolean force = false; + private String classpath, sourcepath; + private LinkedHashMap<File, File> fileToBase = new LinkedHashMap<File, File>(); + private List<File> filesToParse = new ArrayList<File>(); /** If null, output to standard out. */ private File output = null; @@ -88,6 +113,14 @@ public class Delombok { @Mandatory(onlyIfNot={"print", "help"}) private String target; + @Shorthand("c") + @Description("Classpath (analogous to javac -cp option)") + private String classpath; + + @Shorthand("s") + @Description("Sourcepath (analogous to javac -sourcepath option)") + private String sourcepath; + @Description("Files to delombok. Provide either a file, or a directory. If you use a directory, all files in it (recursive) are delombok-ed") @Sequential private List<String> input = new ArrayList<String>(); @@ -138,21 +171,29 @@ public class Delombok { if (args.verbose) delombok.setVerbose(true); if (args.nocopy) delombok.setNoCopy(true); - if (args.print) delombok.setOutputToStandardOut(); - else delombok.setOutput(new File(args.target)); + if (args.print) { + delombok.setOutputToStandardOut(); + } else { + delombok.setOutput(new File(args.target)); + } + + if (args.classpath != null) delombok.setClasspath(args.classpath); + if (args.sourcepath != null) delombok.setSourcepath(args.sourcepath); for (String in : args.input) { try { File f = new File(in); if (f.isFile()) { - delombok.delombok(f.getParentFile(), f.getName()); + delombok.addFile(f.getParentFile(), f.getName()); } else if (f.isDirectory()) { - delombok.delombok(f); + delombok.addDirectory(f); } else if (!f.exists()) { if (!args.quiet) System.err.println("WARNING: does not exist - skipping: " + f); } else { if (!args.quiet) System.err.println("WARNING: not a standard file or directory - skipping: " + f); } + + delombok.delombok(); } catch (Exception e) { if (!args.quiet) { String msg = e.getMessage(); @@ -168,12 +209,12 @@ public class Delombok { } public void setCharset(String charsetName) throws UnsupportedCharsetException { + charset = Charset.forName(charsetName); } - public void setDiagnosticsListener(DiagnosticListener<JavaFileObject> diagnostics) { - parser.setDiagnosticsListener(diagnostics); + if (diagnostics != null) context.put(DiagnosticListener.class, diagnostics); } public void setForceProcess(boolean force) { @@ -184,6 +225,14 @@ public class Delombok { this.feedback = feedback; } + public void setClasspath(String classpath) { + this.classpath = classpath; + } + + public void setSourcepath(String sourcepath) { + this.sourcepath = sourcepath; + } + public void setVerbose(boolean verbose) { this.verbose = verbose; } @@ -204,15 +253,15 @@ public class Delombok { this.output = null; } - public void delombok(File base) throws IOException { - delombok0(false, base, "", 0); + public void addDirectory(File base) throws IOException { + addDirectory0(false, base, "", 0); } - public void process(boolean copy, File base, String name) throws IOException { + public void addDirectory1(boolean copy, File base, String name) throws IOException { File f = new File(base, name); if (f.isFile()) { String extension = getExtension(f); - if (extension.equals("java")) delombok(base, name); + if (extension.equals("java")) addFile(base, name); else if (extension.equals("class")) skipClass(name); else copy(copy, base, name); } else if (!f.exists()) { @@ -222,7 +271,7 @@ public class Delombok { } } - private void delombok0(boolean inHiddenDir, File base, String suffix, int loop) throws IOException { + private void addDirectory0(boolean inHiddenDir, File base, String suffix, int loop) throws IOException { File dir = suffix.isEmpty() ? base : new File(base, suffix); if (dir.isDirectory()) { @@ -236,7 +285,7 @@ public class Delombok { feedback.printf("Only processing java files (not copying non-java files) in %s because it's a hidden directory.\n", canonical(dir)); } for (File f : list) { - delombok0(inHiddenDir || thisDirIsHidden, base, suffix + (suffix.isEmpty() ? "" : File.separator) + f.getName(), loop + 1); + addDirectory0(inHiddenDir || thisDirIsHidden, base, suffix + (suffix.isEmpty() ? "" : File.separator) + f.getName(), loop + 1); } } else { if (!thisDirIsHidden && !noCopy && !inHiddenDir && output != null && !suffix.isEmpty()) { @@ -247,7 +296,7 @@ public class Delombok { } } } else { - process(!inHiddenDir && !noCopy, base, suffix); + addDirectory1(!inHiddenDir && !noCopy, base, suffix); } } @@ -288,34 +337,96 @@ public class Delombok { } } - public void delombok(JavaFileObject file, Writer writer) throws IOException { - ParseResult result = parser.parse(file, force); - result.print(writer); + public void addFile(File base, String fileName) throws IOException { + if (output != null && canonical(base).equals(canonical(output))) throw new IOException( + "DELOMBOK: Output file and input file refer to the same filesystem location. Specify a separate path for output."); + + File f = new File(base, fileName); + filesToParse.add(f); + fileToBase.put(f, base); } - public void delombok(String file, Writer writer) throws IOException { - ParseResult result = parser.parse(file, force); - result.print(writer); + private static <T> com.sun.tools.javac.util.List<T> toJavacList(List<T> list) { + com.sun.tools.javac.util.List<T> out = com.sun.tools.javac.util.List.nil(); + ListIterator<T> li = list.listIterator(list.size()); + while (li.hasPrevious()) out = out.prepend(li.previous()); + return out; } - public void delombok(File base, String fileName) throws IOException { - if (output != null && canonical(base).equals(canonical(output))) throw new IOException( - "DELOMBOK: Output file and input file refer to the same filesystem location. Specify a separate path for output."); + public boolean delombok() throws IOException { + Options options = Options.instance(context); + options.put(OptionName.ENCODING, charset.name()); + if (classpath != null) options.put(OptionName.CLASSPATH, classpath); + if (sourcepath != null) options.put(OptionName.SOURCEPATH, sourcepath); + CommentCollectingScanner.Factory.preRegister(context); - ParseResult result = parser.parse(new File(base, fileName).getAbsolutePath(), force); + JavaCompiler compiler = new JavaCompiler(context); + compiler.keepComments = true; + compiler.genEndPos = true; - if (verbose) feedback.printf("File: %s [%s]\n", fileName, result.isChanged() ? "delombok-ed" : "unchanged"); + List<JCCompilationUnit> roots = new ArrayList<JCCompilationUnit>(); + Map<JCCompilationUnit, Comments> commentsMap = new IdentityHashMap<JCCompilationUnit, Comments>(); + Map<JCCompilationUnit, File> baseMap = new IdentityHashMap<JCCompilationUnit, File>(); + for (File fileToParse : filesToParse) { + Comments comments = new Comments(); + context.put(Comments.class, comments); + + @SuppressWarnings("deprecation") + JCCompilationUnit unit = compiler.parse(fileToParse.getAbsolutePath()); + + commentsMap.put(unit, comments); + baseMap.put(unit, fileToBase.get(fileToParse)); + roots.add(unit); + } - Writer rawWriter = output == null ? createStandardOutWriter() : createFileWriter(output, fileName); - BufferedWriter writer = new BufferedWriter(rawWriter); + if (compiler.errorCount() > 0) return false; + compiler.enterTrees(toJavacList(roots)); - try { - result.print(writer); - } finally { - writer.close(); + for (JCCompilationUnit unit : roots) { + boolean changed = new JavacTransformer(messager).transform(context, Collections.singleton(unit)); + DelombokResult result = new DelombokResult(commentsMap.get(unit).comments, unit, force || changed); + if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged"); + Writer rawWriter; + if (presetWriter != null) rawWriter = presetWriter; + else if (output == null) rawWriter = createStandardOutWriter(); + else rawWriter = createFileWriter(output, baseMap.get(unit), unit.sourcefile.toUri()); + BufferedWriter writer = new BufferedWriter(rawWriter); + try { + result.print(writer); + } finally { + writer.close(); + } + } + + return true; + } + + public static class Comments { + public com.sun.tools.javac.util.List<Comment> comments = com.sun.tools.javac.util.List.nil(); + + void add(Comment comment) { + comments = comments.append(comment); } } + private static final Messager messager = new Messager() { + @Override public void printMessage(Kind kind, CharSequence msg) { + System.out.printf("%s: %s\n", kind, msg); + } + + @Override public void printMessage(Kind kind, CharSequence msg, Element e) { + System.out.printf("%s: %s\n", kind, msg); + } + + @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) { + System.out.printf("%s: %s\n", kind, msg); + } + + @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) { + System.out.printf("%s: %s\n", kind, msg); + } + }; + private static String canonical(File dir) { try { return dir.getCanonicalPath(); @@ -330,8 +441,15 @@ public class Delombok { return idx == -1 ? "" : name.substring(idx+1); } - private Writer createFileWriter(File base, String fileName) throws IOException { - File outFile = new File(base, fileName); + private Writer createFileWriter(File outBase, File inBase, URI file) throws IOException { + URI relative = inBase.toURI().relativize(file); + File outFile; + if (relative.isAbsolute()) { + outFile = new File(outBase, new File(relative).getName()); + } else { + outFile = new File(outBase, relative.getPath()); + } + outFile.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream(outFile); return createUnicodeEscapeWriter(out); diff --git a/src/delombok/lombok/delombok/DelombokResult.java b/src/delombok/lombok/delombok/DelombokResult.java new file mode 100644 index 00000000..717a3bf1 --- /dev/null +++ b/src/delombok/lombok/delombok/DelombokResult.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * + * 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 java.io.IOException; +import java.io.Writer; +import java.util.Date; + +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.util.List; + +public class DelombokResult { + private final List<Comment> comments; + private final JCCompilationUnit compilationUnit; + private final boolean changed; + + public DelombokResult(List<Comment> comments, JCCompilationUnit compilationUnit, boolean changed) { + this.comments = comments; + this.compilationUnit = compilationUnit; + this.changed = changed; + } + + public void print(Writer out) throws IOException { + if (!changed) { + JavaFileObject sourceFile = compilationUnit.getSourceFile(); + if (sourceFile != null) { + out.write(sourceFile.getCharContent(true).toString()); + return; + } + } + + out.write("// Generated by delombok at "); + out.write(String.valueOf(new Date())); + out.write(System.getProperty("line.separator")); + + compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments)); + } + + public boolean isChanged() { + return changed; + } +}
\ No newline at end of file diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 55c0e1bc..57f0a1d8 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -337,7 +337,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { * Traversal methods *************************************************************************/ - /** Exception to propogate IOException through visitXXX methods */ + /** Exception to propagate IOException through visitXXX methods */ private static class UncheckedIOException extends Error { static final long serialVersionUID = -4032692679158424751L; UncheckedIOException(IOException e) { @@ -657,6 +657,11 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } print(" "); + // <Added for delombok by Reinier Zwitserloot> + if ((tree.mods.flags & INTERFACE) != 0) { + removeImplicitModifiersForInterfaceMembers(tree.defs); + } + // </Added for delombok by Reinier Zwitserloot> if ((tree.mods.flags & ENUM) != 0) { printEnumBody(tree.defs); } else { @@ -668,11 +673,28 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } + // Added for delombok by Reinier Zwitserloot + private void removeImplicitModifiersForInterfaceMembers(List<JCTree> defs) { + for (JCTree def :defs) { + if (def instanceof JCVariableDecl) { + ((JCVariableDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.STATIC | Flags.FINAL); + } + if (def instanceof JCMethodDecl) { + ((JCMethodDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.ABSTRACT); + } + if (def instanceof JCClassDecl) { + ((JCClassDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.STATIC); + } + } + } + public void visitMethodDef(JCMethodDecl tree) { try { + boolean isConstructor = tree.name == tree.name.table.fromChars("<init>".toCharArray(), 0, 6); // when producing source output, omit anonymous constructors - if (tree.name == tree.name.table.fromChars("<init>".toCharArray(), 0, 6) && - enclClassName == null) return; + if (isConstructor && enclClassName == null) return; + boolean isGeneratedConstructor = isConstructor && ((tree.mods.flags & Flags.GENERATEDCONSTR) != 0); + if (isGeneratedConstructor) return; println(); align(); printDocComment(tree); printExpr(tree.mods); @@ -1442,9 +1464,13 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { print("@"); printExpr(tree.annotationType); if (tree.args.nonEmpty()) { - print("("); - printExprs(tree.args); - print(")"); + print("("); + if (tree.args.length() == 1 && tree.args.get(0) instanceof JCAssign) { + JCExpression lhs = ((JCAssign)tree.args.get(0)).lhs; + if (lhs instanceof JCIdent && ((JCIdent)lhs).name.toString().equals("value")) tree.args = List.of(((JCAssign)tree.args.get(0)).rhs); + } + printExprs(tree.args); + print(")"); } } catch (IOException e) { throw new UncheckedIOException(e); diff --git a/src/delombok/lombok/delombok/ant/DelombokTask.java b/src/delombok/lombok/delombok/ant/DelombokTask.java index 4a40b874..40c3c63e 100644 --- a/src/delombok/lombok/delombok/ant/DelombokTask.java +++ b/src/delombok/lombok/delombok/ant/DelombokTask.java @@ -32,14 +32,55 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.resources.FileResource; public class DelombokTask extends Task { private File fromDir, toDir; + private Path classpath; + private Path sourcepath; private boolean verbose; private String encoding; private Path path; + public void setClasspath(Path classpath) { + if (this.classpath == null) { + this.classpath = classpath; + } else { + this.classpath.append(classpath); + } + } + + public Path createClasspath() { + if (classpath == null) { + classpath = new Path(getProject()); + } + return classpath.createPath(); + } + + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + public void setSourcepath(Path sourcepath) { + if (this.sourcepath == null) { + this.sourcepath = sourcepath; + } else { + this.sourcepath.append(sourcepath); + } + } + + public Path createSourcepath() { + if (sourcepath == null) { + sourcepath = new Path(getProject()); + } + return sourcepath.createPath(); + } + + public void setSourcepathRef(Reference r) { + createSourcepath().setRefid(r); + } + public void setFrom(File dir) { this.fromDir = dir; } @@ -75,9 +116,12 @@ public class DelombokTask extends Task { throw new BuildException("Unknown charset: " + encoding, getLocation()); } + if (classpath != null) delombok.setClasspath(classpath.toString()); + if (sourcepath != null) delombok.setSourcepath(sourcepath.toString()); + delombok.setOutput(toDir); try { - if (fromDir != null) delombok.delombok(fromDir); + if (fromDir != null) delombok.addDirectory(fromDir); else { Iterator<?> it = path.iterator(); while (it.hasNext()) { @@ -85,12 +129,13 @@ public class DelombokTask extends Task { File baseDir = fileResource.getBaseDir(); if (baseDir == null) { File file = fileResource.getFile(); - delombok.process(false, file.getParentFile(), file.getName()); + delombok.addFile(file.getParentFile(), file.getName()); } else { - delombok.process(false, baseDir, fileResource.getName()); + delombok.addFile(baseDir, fileResource.getName()); } } } + delombok.delombok(); } catch (IOException e) { throw new BuildException("I/O problem during delombok", e, getLocation()); } diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 2ac24a48..399ea357 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -69,6 +69,8 @@ public class EclipsePatcher extends Agent { patchPostCompileHookEcj(sm); } + patchEcjTransformers(sm, ecjOnly); + if (reloadExistingClasses) sm.reloadClasses(instrumentation); } @@ -253,4 +255,77 @@ public class EclipsePatcher extends Agent { .wrapMethod(new Hook("lombok.eclipse.TransformEclipseAST", "transform_swapped", "void", CUD_SIG, PARSER_SIG)) .request(StackRequest.THIS, StackRequest.RETURN_VALUE).build()); } + + private static void patchEcjTransformers(ScriptManager sm, boolean ecj) { + patchHandleVal(sm, ecj); + } + + // Creates a copy of the 'initialization' field on a LocalDeclaration if the type of the LocalDeclaration is 'val', because the completion parser will null this out, + // which in turn stops us from inferring the intended type for 'val x = 5;'. We look at the copy. + // Also patches local declaration to not call .resolveType() on the initializer expression if we've already done so (calling it twice causes weird errors), + // and patches .resolve() on LocalDeclaration itself to just-in-time replace the 'val' vartype with the right one. + + private static void patchHandleVal(ScriptManager sm, boolean ecj) { + final String LOCALDECLARATION_SIG = "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration"; + final String FOREACHSTATEMENT_SIG = "org.eclipse.jdt.internal.compiler.ast.ForeachStatement"; + final String EXPRESSION_SIG = "org.eclipse.jdt.internal.compiler.ast.Expression"; + final String BLOCKSCOPE_SIG = "org.eclipse.jdt.internal.compiler.lookup.BlockScope"; + final String PARSER_SIG = "org.eclipse.jdt.internal.compiler.parser.Parser"; + final String TYPEBINDING_SIG = "org.eclipse.jdt.internal.compiler.lookup.TypeBinding"; + + sm.addScript(ScriptBuilder.exitEarly() + .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG)) + .request(StackRequest.THIS, StackRequest.PARAM1) + .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "handleValForLocalDeclaration", "boolean", LOCALDECLARATION_SIG, BLOCKSCOPE_SIG)) + .build()); + + sm.addScript(ScriptBuilder.replaceMethodCall() + .target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG)) + .methodToReplace(new Hook(EXPRESSION_SIG, "resolveType", TYPEBINDING_SIG, BLOCKSCOPE_SIG)) + .requestExtra(StackRequest.THIS) + .replacementMethod(new Hook("lombok.eclipse.agent.PatchFixes", "skipResolveInitializerIfAlreadyCalled2", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG, LOCALDECLARATION_SIG)) + .build()); + + sm.addScript(ScriptBuilder.exitEarly() + .target(new MethodTarget(FOREACHSTATEMENT_SIG, "resolve", "void", BLOCKSCOPE_SIG)) + .request(StackRequest.THIS, StackRequest.PARAM1) + .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "handleValForForEach", "boolean", FOREACHSTATEMENT_SIG, BLOCKSCOPE_SIG)) + .build()); + + sm.addScript(ScriptBuilder.replaceMethodCall() + .target(new MethodTarget(FOREACHSTATEMENT_SIG, "resolve", "void", BLOCKSCOPE_SIG)) + .methodToReplace(new Hook(EXPRESSION_SIG, "resolveType", TYPEBINDING_SIG, BLOCKSCOPE_SIG)) + .replacementMethod(new Hook("lombok.eclipse.agent.PatchFixes", "skipResolveInitializerIfAlreadyCalled", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG)) + .build()); + + if (!ecj) { + sm.addScript(ScriptBuilder.addField() + .fieldName("$initCopy") + .fieldType("Lorg/eclipse/jdt/internal/compiler/ast/ASTNode;") + .setPublic() + .setTransient() + .targetClass("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") + .build()); + + sm.addScript(ScriptBuilder.addField() + .fieldName("$iterableCopy") + .fieldType("Lorg/eclipse/jdt/internal/compiler/ast/ASTNode;") + .setPublic() + .setTransient() + .targetClass("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") + .build()); + + sm.addScript(ScriptBuilder.wrapReturnValue() + .target(new MethodTarget(PARSER_SIG, "consumeExitVariableWithInitialization", "void")) + .request(StackRequest.THIS) + .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "copyInitializationOfLocalDeclarationForVal", "void", PARSER_SIG)) + .build()); + + sm.addScript(ScriptBuilder.wrapReturnValue() + .target(new MethodTarget(PARSER_SIG, "consumeEnhancedForStatementHeader", "void")) + .request(StackRequest.THIS) + .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "copyInitializationOfForEachIterable", "void", PARSER_SIG)) + .build()); + } + } } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java index daf1cbf2..e2a52929 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java @@ -31,10 +31,28 @@ import java.util.List; import lombok.core.DiagnosticsReceiver; import lombok.core.PostCompiler; +import lombok.eclipse.Eclipse; import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.parser.Parser; public class PatchFixes { public static int fixRetrieveStartingCatchPosition(int in) { @@ -78,7 +96,7 @@ public class PatchFixes { boolean isGenerated = internalNode.getClass().getField("$generatedBy").get(internalNode) != null; if (isGenerated) { domNode.getClass().getField("$isGenerated").set(domNode, true); - domNode.setFlags(domNode.getFlags() & ~ASTNode.ORIGINAL); + domNode.setFlags(domNode.getFlags() & ~org.eclipse.jdt.core.dom.ASTNode.ORIGINAL); } } @@ -127,4 +145,178 @@ public class PatchFixes { String fileName = path + "/" + name; return new BufferedOutputStream(PostCompiler.wrapOutputStream(out, fileName, DiagnosticsReceiver.CONSOLE)); } + + private static Field astStackField, astPtrField; + + static { + try { + astStackField = Parser.class.getDeclaredField("astStack"); + astStackField.setAccessible(true); + astPtrField = Parser.class.getDeclaredField("astPtr"); + astPtrField.setAccessible(true); + } catch (Exception e) { + // Most likely we're in ecj or some other plugin usage of the eclipse compiler. No need for this. + } + } + + public static void copyInitializationOfForEachIterable(Parser parser) { + ASTNode[] astStack; + int astPtr; + try { + astStack = (ASTNode[]) astStackField.get(parser); + astPtr = (Integer)astPtrField.get(parser); + } catch (Exception e) { + // Most likely we're in ecj or some other plugin usage of the eclipse compiler. No need for this. + return; + } + + ForeachStatement foreachDecl = (ForeachStatement) astStack[astPtr]; + ASTNode init = foreachDecl.collection; + if (init == null) return; + if (foreachDecl.elementVariable != null && foreachDecl.elementVariable.type instanceof SingleTypeReference) { + SingleTypeReference ref = (SingleTypeReference) foreachDecl.elementVariable.type; + if (ref.token == null || ref.token.length != 3 || ref.token[0] != 'v' || ref.token[1] != 'a' || ref.token[2] != 'l') return; + } else return; + + try { + if (iterableCopyField != null) iterableCopyField.set(foreachDecl.elementVariable, init); + } catch (Exception e) { + // In ecj mode this field isn't there and we don't need the copy anyway, so, we ignore the exception. + } + } + + public static void copyInitializationOfLocalDeclarationForVal(Parser parser) { + ASTNode[] astStack; + int astPtr; + try { + astStack = (ASTNode[]) astStackField.get(parser); + astPtr = (Integer)astPtrField.get(parser); + } catch (Exception e) { + // Most likely we're in ecj or some other plugin usage of the eclipse compiler. No need for this. + return; + } + AbstractVariableDeclaration variableDecl = (AbstractVariableDeclaration) astStack[astPtr]; + if (!(variableDecl instanceof LocalDeclaration)) return; + ASTNode init = variableDecl.initialization; + if (init == null) return; + if (variableDecl.type instanceof SingleTypeReference) { + SingleTypeReference ref = (SingleTypeReference) variableDecl.type; + if (ref.token == null || ref.token.length != 3 || ref.token[0] != 'v' || ref.token[1] != 'a' || ref.token[2] != 'l') return; + } else return; + + try { + if (initCopyField != null) initCopyField.set(variableDecl, init); + } catch (Exception e) { + // In ecj mode this field isn't there and we don't need the copy anyway, so, we ignore the exception. + } + } + + private static Field initCopyField, iterableCopyField; + + static { + try { + initCopyField = LocalDeclaration.class.getDeclaredField("$initCopy"); + iterableCopyField = LocalDeclaration.class.getDeclaredField("$iterableCopy"); + } catch (Throwable t) { + //ignore - no $initCopy exists when running in ecj. + } + } + + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { + if (forEach.elementVariable != null && forEach.elementVariable.type instanceof SingleTypeReference) { + char[] token = ((SingleTypeReference)forEach.elementVariable.type).token; + if (token == null || token.length != 3) return false; + else if (token[0] != 'v' || token[1] != 'a' || token[2] != 'l') return false; + } else return false; + + TypeBinding component = getForEachComponentType(forEach.collection, scope); + TypeReference replacement = Eclipse.makeType(component, forEach.elementVariable.type, false); + + forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; + forEach.elementVariable.type = replacement != null ? replacement : + new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, Eclipse.poss(forEach.elementVariable.type, 3)); + + return false; + } + + private static TypeBinding getForEachComponentType(Expression collection, BlockScope scope) { + if (collection != null) { + TypeBinding resolved = collection.resolveType(scope); + if (resolved.isArrayType()) { + resolved = ((ArrayBinding) resolved).elementsType(); + return resolved; + } else if (resolved instanceof ReferenceBinding) { + ReferenceBinding iterableType = ((ReferenceBinding)resolved).findSuperTypeOriginatingFrom(TypeIds.T_JavaLangIterable, false); + + TypeBinding[] arguments = null; + if (iterableType != null) switch (iterableType.kind()) { + case Binding.GENERIC_TYPE : // for (T t : Iterable<T>) - in case used inside Iterable itself + arguments = iterableType.typeVariables(); + break; + case Binding.PARAMETERIZED_TYPE : // for(E e : Iterable<E>) + arguments = ((ParameterizedTypeBinding)iterableType).arguments; + break; + } + + if (arguments != null && arguments.length == 1) { + return arguments[0]; + } + } + } + + return null; + } + + public static boolean handleValForLocalDeclaration(LocalDeclaration local, BlockScope scope) { + if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false; + boolean decomponent = false; + + if (local.type instanceof SingleTypeReference) { + char[] token = ((SingleTypeReference)local.type).token; + if (token == null || token.length != 3) return false; + else if (token[0] != 'v' || token[1] != 'a' || token[2] != 'l') return false; + } else return false; + + Expression init = local.initialization; + if (init == null && initCopyField != null) { + try { + init = (Expression) initCopyField.get(local); + } catch (Exception e) { + } + } + + if (init == null && iterableCopyField != null) { + try { + init = (Expression) iterableCopyField.get(local); + decomponent = true; + } catch (Exception e) { + } + } + + TypeReference replacement = null; + if (init != null && decomponent) { + } + + if (init != null) { + TypeBinding resolved = decomponent ? getForEachComponentType(init, scope) : init.resolveType(scope); + if (resolved != null) { + replacement = Eclipse.makeType(resolved, local.type, false); + } + } + + local.modifiers |= ClassFileConstants.AccFinal; + local.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, Eclipse.poss(local.type, 3)); + + return false; + } + + public static TypeBinding skipResolveInitializerIfAlreadyCalled(Expression expr, BlockScope scope) { + if (expr.resolvedType != null) return expr.resolvedType; + return expr.resolveType(scope); + } + + public static TypeBinding skipResolveInitializerIfAlreadyCalled2(Expression expr, BlockScope scope, LocalDeclaration decl) { + if (decl != null && LocalDeclaration.class.equals(decl.getClass()) && expr.resolvedType != null) return expr.resolvedType; + return expr.resolveType(scope); + } } diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index 4241646b..7d5992be 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -37,12 +37,12 @@ public abstract class AbstractRunTests { public void compareFile(DirectoryRunner.TestParams params, File file) throws Throwable { StringBuilder messages = new StringBuilder(); - StringWriter result = new StringWriter(); - transformCode(messages, result, file); + StringWriter writer = new StringWriter(); + transformCode(messages, writer, file); compare( file.getName(), readFile(params.getAfterDirectory(), file, false), - result.toString(), + writer.toString(), readFile(params.getMessagesDirectory(), file, true), messages.toString(), params.printErrors()); @@ -111,6 +111,9 @@ public abstract class AbstractRunTests { private static void compareContent(String name, String expectedFile, String actualFile) { String[] expectedLines = expectedFile.split("(\\r?\\n)"); String[] actualLines = actualFile.split("(\\r?\\n)"); + if (expectedLines[0].startsWith("// Generated by delombok at ")) { + expectedLines[0] = ""; + } if (actualLines[0].startsWith("// Generated by delombok at ")) { actualLines[0] = ""; } diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java index 50fad33e..59a0ee89 100644 --- a/test/core/src/lombok/RunTestsViaDelombok.java +++ b/test/core/src/lombok/RunTestsViaDelombok.java @@ -51,6 +51,9 @@ public class RunTestsViaDelombok extends AbstractRunTests { } }); - delombok.delombok(file.getAbsolutePath(), result); + delombok.addFile(file.getParentFile(), file.getName()); + delombok.setSourcepath(file.getParentFile().getAbsolutePath()); + delombok.setWriter(result); + delombok.delombok(); } } diff --git a/test/pretty/resource/after/Interfaces.java b/test/pretty/resource/after/Interfaces.java index c8a5cca4..c5008f2b 100644 --- a/test/pretty/resource/after/Interfaces.java +++ b/test/pretty/resource/after/Interfaces.java @@ -2,6 +2,6 @@ interface Interfaces { int x = 10; void y(); - public static final int a = 20; - public abstract void b(); + int a = 20; + void b(); } diff --git a/test/pretty/resource/before/Annotation.java b/test/pretty/resource/before/Annotation.java index edd1a5e7..24868acd 100644 --- a/test/pretty/resource/before/Annotation.java +++ b/test/pretty/resource/before/Annotation.java @@ -1,3 +1,4 @@ +//ignore @SuppressWarnings("all") class Annotation { @Override diff --git a/test/transform/resource/after-delombok/CleanupName.java b/test/transform/resource/after-delombok/CleanupName.java index cd29eb68..0201008e 100644 --- a/test/transform/resource/after-delombok/CleanupName.java +++ b/test/transform/resource/after-delombok/CleanupName.java @@ -4,7 +4,9 @@ class CleanupName { try { System.out.println(o); } finally { - o.toString(); + if (o != null) { + o.toString(); + } } } void test2() { @@ -12,7 +14,9 @@ class CleanupName { try { System.out.println(o); } finally { - o.toString(); + if (o != null) { + o.toString(); + } } } } diff --git a/test/transform/resource/after-delombok/CleanupPlain.java b/test/transform/resource/after-delombok/CleanupPlain.java index 35d51543..1a19442f 100644 --- a/test/transform/resource/after-delombok/CleanupPlain.java +++ b/test/transform/resource/after-delombok/CleanupPlain.java @@ -9,10 +9,14 @@ class CleanupPlain { out.flush(); } } finally { - out.close(); + if (out != null) { + out.close(); + } } } finally { - in.close(); + if (in != null) { + in.close(); + } } } } diff --git a/test/transform/resource/after-delombok/DataExtended.java b/test/transform/resource/after-delombok/DataExtended.java index 6f55bc2c..be1c3b74 100644 --- a/test/transform/resource/after-delombok/DataExtended.java +++ b/test/transform/resource/after-delombok/DataExtended.java @@ -15,12 +15,16 @@ class DataExtended { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof DataExtended)) return false; final DataExtended other = (DataExtended)o; + if (!other.canEqual(this)) return false; if (this.getX() != other.getX()) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof DataExtended; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { diff --git a/test/transform/resource/after-delombok/DataIgnore.java b/test/transform/resource/after-delombok/DataIgnore.java index 7e81432d..9f2a7d79 100644 --- a/test/transform/resource/after-delombok/DataIgnore.java +++ b/test/transform/resource/after-delombok/DataIgnore.java @@ -14,12 +14,16 @@ class DataIgnore { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof DataIgnore)) return false; final DataIgnore other = (DataIgnore)o; + if (!other.canEqual(this)) return false; if (this.getX() != other.getX()) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof DataIgnore; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { @@ -33,4 +37,4 @@ class DataIgnore { public java.lang.String toString() { return "DataIgnore(x=" + this.getX() + ")"; } -} +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/DataOnLocalClass.java b/test/transform/resource/after-delombok/DataOnLocalClass.java index bb3f564d..02101a81 100644 --- a/test/transform/resource/after-delombok/DataOnLocalClass.java +++ b/test/transform/resource/after-delombok/DataOnLocalClass.java @@ -23,13 +23,17 @@ class DataOnLocalClass1 { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof Local)) return false; final Local other = (Local)o; + if (!other.canEqual(this)) return false; if (this.getX() != other.getX()) return false; if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof Local; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { @@ -73,12 +77,16 @@ class DataOnLocalClass2 { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof InnerLocal)) return false; final InnerLocal other = (InnerLocal)o; + if (!other.canEqual(this)) return false; if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof InnerLocal; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { @@ -105,12 +113,16 @@ class DataOnLocalClass2 { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof Local)) return false; final Local other = (Local)o; + if (!other.canEqual(this)) return false; if (this.getX() != other.getX()) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof Local; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { diff --git a/test/transform/resource/after-delombok/DataPlain.java b/test/transform/resource/after-delombok/DataPlain.java index 1e11a33d..ef86f9d7 100644 --- a/test/transform/resource/after-delombok/DataPlain.java +++ b/test/transform/resource/after-delombok/DataPlain.java @@ -22,13 +22,17 @@ class Data1 { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof Data1)) return false; final Data1 other = (Data1)o; + if (!other.canEqual(this)) return false; if (this.getX() != other.getX()) return false; if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof Data1; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { @@ -68,13 +72,17 @@ class Data2 { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof Data2)) return false; final Data2 other = (Data2)o; + if (!other.canEqual(this)) return false; if (this.getX() != other.getX()) return false; if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof Data2; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { @@ -90,3 +98,87 @@ class Data2 { return "Data2(x=" + this.getX() + ", name=" + this.getName() + ")"; } } +final class Data3 { + final int x; + String name; + @java.beans.ConstructorProperties({"x"}) + @java.lang.SuppressWarnings("all") + public Data3(final int x) { + this.x = x; + } + @java.lang.SuppressWarnings("all") + public int getX() { + return this.x; + } + @java.lang.SuppressWarnings("all") + public String getName() { + return this.name; + } + @java.lang.SuppressWarnings("all") + public void setName(final String name) { + this.name = name; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Data3)) return false; + final Data3 other = (Data3)o; + if (this.getX() != other.getX()) return false; + if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = result * PRIME + this.getX(); + result = result * PRIME + (this.getName() == null ? 0 : this.getName().hashCode()); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Data3(x=" + this.getX() + ", name=" + this.getName() + ")"; + } +} +final class Data4 extends java.util.Timer { + final int x; + Data4() { + super(); + } + @java.lang.SuppressWarnings("all") + public int getX() { + return this.x; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "Data4(x=" + this.getX() + ")"; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof Data4)) return false; + final Data4 other = (Data4)o; + if (!other.canEqual(this)) return false; + if (!super.equals(o)) return false; + if (this.getX() != other.getX()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof Data4; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = result * PRIME + super.hashCode(); + result = result * PRIME + this.getX(); + return result; + } +} diff --git a/test/transform/resource/after-delombok/DataWithGetter.java b/test/transform/resource/after-delombok/DataWithGetter.java index 28b8dee0..1e181370 100644 --- a/test/transform/resource/after-delombok/DataWithGetter.java +++ b/test/transform/resource/after-delombok/DataWithGetter.java @@ -19,14 +19,18 @@ class DataWithGetter { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof DataWithGetter)) return false; final DataWithGetter other = (DataWithGetter)o; + if (!other.canEqual(this)) return false; if (this.getX() != other.getX()) return false; if (this.getY() != other.getY()) return false; if (this.getZ() == null ? other.getZ() != null : !this.getZ().equals(other.getZ())) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof DataWithGetter; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { diff --git a/test/transform/resource/after-delombok/DataWithGetterNone.java b/test/transform/resource/after-delombok/DataWithGetterNone.java index 161c70f9..b1cab7cf 100644 --- a/test/transform/resource/after-delombok/DataWithGetterNone.java +++ b/test/transform/resource/after-delombok/DataWithGetterNone.java @@ -19,14 +19,18 @@ class DataWithGetterNone { @java.lang.SuppressWarnings("all") public boolean equals(final java.lang.Object o) { if (o == this) return true; - if (o == null) return false; - if (o.getClass() != this.getClass()) return false; + if (!(o instanceof DataWithGetterNone)) return false; final DataWithGetterNone other = (DataWithGetterNone)o; + if (!other.canEqual(this)) return false; if (this.x != other.x) return false; if (this.y != other.y) return false; if (this.z == null ? other.z != null : !this.z.equals(other.z)) return false; return true; } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof DataWithGetterNone; + } @java.lang.Override @java.lang.SuppressWarnings("all") public int hashCode() { diff --git a/test/transform/resource/after-delombok/LoggerCommons.java b/test/transform/resource/after-delombok/LoggerCommons.java new file mode 100644 index 00000000..a55aa336 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerCommons.java @@ -0,0 +1,9 @@ +class LoggerCommons { + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LoggerCommons.class); +} +class LoggerCommonsString { + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(String.class); +} +class LoggerCommonsJavaLangString { + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(java.lang.String.class); +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerJul.java b/test/transform/resource/after-delombok/LoggerJul.java new file mode 100644 index 00000000..51f19926 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerJul.java @@ -0,0 +1,9 @@ +class LoggerJul { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggerJul.class.getName()); +} +class LoggerJulString { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(String.class.getName()); +} +class LoggerJulJavaLangString { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(java.lang.String.class.getName()); +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerLog4j.java b/test/transform/resource/after-delombok/LoggerLog4j.java new file mode 100644 index 00000000..e946c858 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerLog4j.java @@ -0,0 +1,9 @@ +class LoggerLog4j { + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LoggerLog4j.class); +} +class LoggerLog4jString { + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(String.class); +} +class LoggerLog4jJavaLangString { + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(java.lang.String.class); +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4j.java b/test/transform/resource/after-delombok/LoggerSlf4j.java new file mode 100644 index 00000000..c7c84631 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4j.java @@ -0,0 +1,8 @@ +class LoggerSlf4j { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4j.class); +} +class LoggerSlf4jOuter { + static class Inner { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Inner.class); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4jAlreadyExists.java b/test/transform/resource/after-delombok/LoggerSlf4jAlreadyExists.java new file mode 100644 index 00000000..a7cd9409 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jAlreadyExists.java @@ -0,0 +1,3 @@ +class LoggerSlf4jAlreadyExists { + int log; +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4jClassOfArray.java b/test/transform/resource/after-delombok/LoggerSlf4jClassOfArray.java new file mode 100644 index 00000000..00b44d5c --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jClassOfArray.java @@ -0,0 +1,6 @@ +class LoggerSlf4jClassOfArray { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(String[].class); +} +class LoggerSlf4jClassOfArrayJLS { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.lang.String[].class); +} diff --git a/test/transform/resource/after-delombok/LoggerSlf4jOnNonType.java b/test/transform/resource/after-delombok/LoggerSlf4jOnNonType.java new file mode 100644 index 00000000..4c944172 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jOnNonType.java @@ -0,0 +1,4 @@ +class LoggerSlf4jOnNonType { + void foo() { + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4jTypes.java b/test/transform/resource/after-delombok/LoggerSlf4jTypes.java new file mode 100644 index 00000000..4950bc88 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jTypes.java @@ -0,0 +1,17 @@ +interface LoggerSlf4jTypesInterface { +} +@interface LoggerSlf4jTypesAnnotation { +} +enum LoggerSlf4jTypesEnum { +; + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnum.class); +} +enum LoggerSlf4jTypesEnumWithElement { + FOO; + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnumWithElement.class); +} +interface LoggerSlf4jTypesInterfaceOuter { + class Inner { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Inner.class); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/LoggerSlf4jWithClass.java b/test/transform/resource/after-delombok/LoggerSlf4jWithClass.java new file mode 100644 index 00000000..b4e2181e --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jWithClass.java @@ -0,0 +1,12 @@ +class LoggerSlf4jWithClass { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(String.class); +} +class LoggerSlf4jWithClassList { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.util.List.class); +} +class LoggerSlf4jWithClassValue { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.lang.String.class); +} +class LoggerSlf4jWithClassVoid { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(void.class); +} diff --git a/test/transform/resource/after-delombok/LoggerSlf4jWithPackage.java b/test/transform/resource/after-delombok/LoggerSlf4jWithPackage.java new file mode 100644 index 00000000..b337bd02 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerSlf4jWithPackage.java @@ -0,0 +1,9 @@ +package before; +class LoggerSlf4jWithPackage { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jWithPackage.class); +} +class LoggerSlf4jWithPackageOuter { + static class Inner { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Inner.class); + } +} diff --git a/test/transform/resource/after-delombok/ValComplex.java b/test/transform/resource/after-delombok/ValComplex.java new file mode 100644 index 00000000..54ef5c78 --- /dev/null +++ b/test/transform/resource/after-delombok/ValComplex.java @@ -0,0 +1,20 @@ +public class ValComplex { + private ValSimple field = new ValSimple(); + private static final int CONSTANT = 20; + public void testReferencingOtherFiles() { + final java.lang.String shouldBeString = field.method(); + final int shouldBeInt = CONSTANT; + final java.lang.Object lock = new Object(); + synchronized (lock) { + final int field = 20; //Shadowing + final int inner = 10; + switch (field) { + case 5: + final java.lang.String shouldBeString2 = shouldBeString; + final int innerInner = inner; + + } + } + final ValSimple shouldBeValSimple = field; //Unshadowing + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValErrors.java b/test/transform/resource/after-delombok/ValErrors.java new file mode 100644 index 00000000..5ac785ab --- /dev/null +++ b/test/transform/resource/after-delombok/ValErrors.java @@ -0,0 +1,8 @@ +public class ValErrors { + public void nullType() { + final val a = null; + } + public void unresolvableExpression() { + final val c = d; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValInFor.java b/test/transform/resource/after-delombok/ValInFor.java new file mode 100644 index 00000000..a04d0f0c --- /dev/null +++ b/test/transform/resource/after-delombok/ValInFor.java @@ -0,0 +1,19 @@ +public class ValInFor { + { + final int x = 10; + final int x2 = -1; + final java.lang.String a = "Hello"; + for (final int y = x, z = x2; y < 20; y++) { + final int q = y; + final int w = z; + final java.lang.String v = a; + } + } +/* public void enhancedFor() { + java.util.List<String> list = java.util.Arrays.asList("Hello, World!"); + for (val shouldBeString : list) { + System.out.println(shouldBeString.toLowerCase()); + val shouldBeString2 = shouldBeString; + } + }*/ +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValLessSimple.java b/test/transform/resource/after-delombok/ValLessSimple.java new file mode 100644 index 00000000..678b419e --- /dev/null +++ b/test/transform/resource/after-delombok/ValLessSimple.java @@ -0,0 +1,26 @@ +public class ValLessSimple { + private short field2 = 5; + private String method() { + return "method"; + } + private double method2() { + return 2.0; + } + { + System.out.println("Hello"); + final int z = 20; + final int x = 10; + final int a = z; + final short y = field2; + } + private void testVal(String param) { + final java.lang.String fieldV = field; + final int a = 10; + final int b = 20; + { + final java.lang.String methodV = method(); + final java.lang.String foo = fieldV + methodV; + } + } + private String field = "field"; +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValSimple.java b/test/transform/resource/after-delombok/ValSimple.java new file mode 100644 index 00000000..b2783eac --- /dev/null +++ b/test/transform/resource/after-delombok/ValSimple.java @@ -0,0 +1,24 @@ +public class ValSimple { + private String field = "field"; + private short field2 = 5; + + private String method() { + return "method"; + } + + private double method2() { + return 2.0; + } + + private void testVal(String param) { + final java.lang.String fieldV = field; + final java.lang.String methodV = method(); + final java.lang.String paramV = param; + final java.lang.String valOfVal = fieldV; + final java.lang.String operatorV = fieldV + valOfVal; + final short fieldW = field2; + final double methodW = method2(); + byte localVar = 3; + final int operatorW = fieldW + localVar; + } +} diff --git a/test/transform/resource/after-delombok/ValWeirdTypes.java b/test/transform/resource/after-delombok/ValWeirdTypes.java new file mode 100644 index 00000000..66212906 --- /dev/null +++ b/test/transform/resource/after-delombok/ValWeirdTypes.java @@ -0,0 +1,47 @@ +import java.util.*; +public class ValWeirdTypes<Z> { + private final List<Z> fieldList; + public void testGenerics() { + List<String> list = new ArrayList<String>(); + list.add("Hello, World!"); + final java.lang.String shouldBeString = list.get(0); + final java.util.List<java.lang.String> shouldBeListOfString = list; + final java.util.List<java.lang.String> shouldBeListOfStringToo = Arrays.asList("hello", "world"); + final java.lang.String shouldBeString2 = shouldBeListOfString.get(0); + } + public void testGenericsInference() { + final java.util.List<java.lang.Object> huh = Collections.emptyList(); + final java.util.List<java.lang.Number> huh2 = Collections.<Number>emptyList(); + } + public void testPrimitives() { + final int x = 10; + final long y = 5 + 3L; + } + public void testAnonymousInnerClass() { + final java.lang.Runnable y = new Runnable(){ + public void run() { + } + }; + } + public <T extends Number>void testTypeParams(List<T> param) { + final T t = param.get(0); + final Z z = fieldList.get(0); + final java.util.List<T> k = param; + final java.util.List<Z> y = fieldList; + } + public void testBounds(List<? extends Number> lower, List<? super Number> upper) { + final java.lang.Number a = lower.get(0); + final java.lang.Object b = upper.get(0); + final java.util.List<? extends java.lang.Number> c = lower; + final java.util.List<? super java.lang.Number> d = upper; + List<?> unbound = lower; + final java.util.List<?> e = unbound; + } + public void testCompound() { + final java.util.ArrayList<java.lang.String> a = new ArrayList<String>(); + final java.util.Vector<java.lang.String> b = new Vector<String>(); + final boolean c = 1 < System.currentTimeMillis(); + final java.util.AbstractList<java.lang.String> d = c ? a : b; + java.util.RandomAccess confirm = c ? a : b; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ClassNamedAfterGetter.java b/test/transform/resource/after-ecj/ClassNamedAfterGetter.java index fdb6f122..fb9df0ea 100644 --- a/test/transform/resource/after-ecj/ClassNamedAfterGetter.java +++ b/test/transform/resource/after-ecj/ClassNamedAfterGetter.java @@ -1,9 +1,9 @@ class GetFoo { private @lombok.Getter int foo; - GetFoo() { - super(); - } public @java.lang.SuppressWarnings("all") int getFoo() { return this.foo; } + GetFoo() { + super(); + } } diff --git a/test/transform/resource/after-ecj/CleanupName.java b/test/transform/resource/after-ecj/CleanupName.java index 944a81e1..4011721b 100644 --- a/test/transform/resource/after-ecj/CleanupName.java +++ b/test/transform/resource/after-ecj/CleanupName.java @@ -10,7 +10,10 @@ class CleanupName { } finally { - o.toString(); + if ((o != null)) + { + o.toString(); + } } } void test2() { @@ -21,7 +24,10 @@ class CleanupName { } finally { - o.toString(); + if ((o != null)) + { + o.toString(); + } } } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/CleanupPlain.java b/test/transform/resource/after-ecj/CleanupPlain.java index 6754b4f6..fe8d7571 100644 --- a/test/transform/resource/after-ecj/CleanupPlain.java +++ b/test/transform/resource/after-ecj/CleanupPlain.java @@ -18,12 +18,18 @@ class CleanupPlain { } finally { - out.close(); + if ((out != null)) + { + out.close(); + } } } finally { - in.close(); + if ((in != null)) + { + in.close(); + } } } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/CommentsInterspersed.java b/test/transform/resource/after-ecj/CommentsInterspersed.java index d708ad72..60c69aed 100644 --- a/test/transform/resource/after-ecj/CommentsInterspersed.java +++ b/test/transform/resource/after-ecj/CommentsInterspersed.java @@ -2,11 +2,11 @@ import lombok.Getter; public class CommentsInterspersed { private int x; private @Getter String test = "foo"; + public @java.lang.SuppressWarnings("all") String getTest() { + return this.test; + } public CommentsInterspersed() { super(); } public native void gwtTest(); - public @java.lang.SuppressWarnings("all") String getTest() { - return this.test; - } } diff --git a/test/transform/resource/after-ecj/DataExtended.java b/test/transform/resource/after-ecj/DataExtended.java index b7be8bcf..10a66547 100644 --- a/test/transform/resource/after-ecj/DataExtended.java +++ b/test/transform/resource/after-ecj/DataExtended.java @@ -12,15 +12,18 @@ public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof DataExtended))) return false; final DataExtended other = (DataExtended) o; + if ((! other.canEqual(this))) + return false; if ((this.getX() != other.getX())) return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof DataExtended); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; diff --git a/test/transform/resource/after-ecj/DataIgnore.java b/test/transform/resource/after-ecj/DataIgnore.java index df2254c8..13c8e2f7 100644 --- a/test/transform/resource/after-ecj/DataIgnore.java +++ b/test/transform/resource/after-ecj/DataIgnore.java @@ -11,15 +11,18 @@ public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof DataIgnore))) return false; final DataIgnore other = (DataIgnore) o; + if ((! other.canEqual(this))) + return false; if ((this.getX() != other.getX())) return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof DataIgnore); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; diff --git a/test/transform/resource/after-ecj/DataOnLocalClass.java b/test/transform/resource/after-ecj/DataOnLocalClass.java index a17033c2..b987b967 100644 --- a/test/transform/resource/after-ecj/DataOnLocalClass.java +++ b/test/transform/resource/after-ecj/DataOnLocalClass.java @@ -23,17 +23,20 @@ class DataOnLocalClass1 { public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof Local))) return false; final Local other = (Local) o; + if ((! other.canEqual(this))) + return false; if ((this.getX() != other.getX())) return false; if (((this.getName() == null) ? (other.getName() != null) : (! this.getName().equals(other.getName())))) return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Local); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; @@ -69,15 +72,18 @@ class DataOnLocalClass2 { public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof InnerLocal))) return false; final InnerLocal other = (InnerLocal) o; + if ((! other.canEqual(this))) + return false; if (((this.getName() == null) ? (other.getName() != null) : (! this.getName().equals(other.getName())))) return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof InnerLocal); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; @@ -99,15 +105,18 @@ class DataOnLocalClass2 { public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof Local))) return false; final Local other = (Local) o; + if ((! other.canEqual(this))) + return false; if ((this.getX() != other.getX())) return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Local); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; diff --git a/test/transform/resource/after-ecj/DataPlain.java b/test/transform/resource/after-ecj/DataPlain.java index b6e385f3..d704a249 100644 --- a/test/transform/resource/after-ecj/DataPlain.java +++ b/test/transform/resource/after-ecj/DataPlain.java @@ -18,17 +18,20 @@ import lombok.Data; public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof Data1))) return false; final Data1 other = (Data1) o; + if ((! other.canEqual(this))) + return false; if ((this.getX() != other.getX())) return false; if (((this.getName() == null) ? (other.getName() != null) : (! this.getName().equals(other.getName())))) return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Data1); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; @@ -59,17 +62,20 @@ import lombok.Data; public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof Data2))) return false; final Data2 other = (Data2) o; + if ((! other.canEqual(this))) + return false; if ((this.getX() != other.getX())) return false; if (((this.getName() == null) ? (other.getName() != null) : (! this.getName().equals(other.getName())))) return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Data2); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; @@ -81,3 +87,78 @@ import lombok.Data; return (((("Data2(x=" + this.getX()) + ", name=") + this.getName()) + ")"); } } +final @Data class Data3 { + final int x; + String name; + public @java.beans.ConstructorProperties({"x"}) @java.lang.SuppressWarnings("all") Data3(final int x) { + super(); + this.x = x; + } + public @java.lang.SuppressWarnings("all") int getX() { + return this.x; + } + public @java.lang.SuppressWarnings("all") String getName() { + return this.name; + } + public @java.lang.SuppressWarnings("all") void setName(final String name) { + this.name = name; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Data3))) + return false; + final Data3 other = (Data3) o; + if ((this.getX() != other.getX())) + return false; + if (((this.getName() == null) ? (other.getName() != null) : (! this.getName().equals(other.getName())))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 31; + int result = 1; + result = ((result * PRIME) + this.getX()); + result = ((result * PRIME) + ((this.getName() == null) ? 0 : this.getName().hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("Data3(x=" + this.getX()) + ", name=") + this.getName()) + ")"); + } +} +final @Data @lombok.EqualsAndHashCode(callSuper = true) class Data4 extends java.util.Timer { + final int x; + public @java.lang.SuppressWarnings("all") int getX() { + return this.x; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("Data4(x=" + this.getX()) + ")"); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof Data4))) + return false; + final Data4 other = (Data4) o; + if ((! other.canEqual(this))) + return false; + if ((! super.equals(o))) + return false; + if ((this.getX() != other.getX())) + return false; + return true; + } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof Data4); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 31; + int result = 1; + result = ((result * PRIME) + super.hashCode()); + result = ((result * PRIME) + this.getX()); + return result; + } + Data4() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/DataWithGetter.java b/test/transform/resource/after-ecj/DataWithGetter.java index abf1dc64..904ae0fa 100644 --- a/test/transform/resource/after-ecj/DataWithGetter.java +++ b/test/transform/resource/after-ecj/DataWithGetter.java @@ -15,11 +15,11 @@ public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof DataWithGetter))) return false; final DataWithGetter other = (DataWithGetter) o; + if ((! other.canEqual(this))) + return false; if ((this.getX() != other.getX())) return false; if ((this.getY() != other.getY())) @@ -28,6 +28,9 @@ return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof DataWithGetter); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; diff --git a/test/transform/resource/after-ecj/DataWithGetterNone.java b/test/transform/resource/after-ecj/DataWithGetterNone.java index 97509c07..0172f4f3 100644 --- a/test/transform/resource/after-ecj/DataWithGetterNone.java +++ b/test/transform/resource/after-ecj/DataWithGetterNone.java @@ -15,11 +15,11 @@ public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { if ((o == this)) return true; - if ((o == null)) - return false; - if ((o.getClass() != this.getClass())) + if ((! (o instanceof DataWithGetterNone))) return false; final DataWithGetterNone other = (DataWithGetterNone) o; + if ((! other.canEqual(this))) + return false; if ((this.x != other.x)) return false; if ((this.y != other.y)) @@ -28,6 +28,9 @@ return false; return true; } + public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof DataWithGetterNone); + } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 31; int result = 1; diff --git a/test/transform/resource/after-ecj/GetterAccessLevel.java b/test/transform/resource/after-ecj/GetterAccessLevel.java index 14edfb56..f0de95e7 100644 --- a/test/transform/resource/after-ecj/GetterAccessLevel.java +++ b/test/transform/resource/after-ecj/GetterAccessLevel.java @@ -10,9 +10,6 @@ class GetterAccessLevel { @lombok.Getter(lombok.AccessLevel.PROTECTED) String protectedString; @lombok.Getter(lombok.AccessLevel.PUBLIC) String publicString; @lombok.Getter(value = lombok.AccessLevel.PUBLIC) String value; - GetterAccessLevel() { - super(); - } private @java.lang.SuppressWarnings("all") boolean isPrivate() { return this.isPrivate; } @@ -40,4 +37,7 @@ class GetterAccessLevel { public @java.lang.SuppressWarnings("all") String getValue() { return this.value; } + GetterAccessLevel() { + super(); + } } diff --git a/test/transform/resource/after-ecj/GetterAlreadyExists.java b/test/transform/resource/after-ecj/GetterAlreadyExists.java index 959b6a64..f491f147 100644 --- a/test/transform/resource/after-ecj/GetterAlreadyExists.java +++ b/test/transform/resource/after-ecj/GetterAlreadyExists.java @@ -27,27 +27,27 @@ class Getter3 { } class Getter4 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter4() { super(); } String hasFoo() { return null; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter5 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter5() { super(); } String isFoo() { return null; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter6 { @lombok.Getter String foo; @@ -60,27 +60,27 @@ class Getter6 { } class Getter7 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter7() { super(); } boolean hasFoo() { return false; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter8 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter8() { super(); } boolean isFoo() { return false; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter9 { @lombok.Getter String foo; @@ -120,27 +120,27 @@ class Getter12 { } class Getter13 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter13() { super(); } static boolean hasFoo() { return false; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter14 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter14() { super(); } static boolean isFoo() { return false; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter15 { @lombok.Getter String foo; @@ -153,27 +153,27 @@ class Getter15 { } class Getter16 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter16() { super(); } static String hasFoo() { return false; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter17 { @lombok.Getter String foo; + public @java.lang.SuppressWarnings("all") String getFoo() { + return this.foo; + } Getter17() { super(); } static String isFoo() { return false; } - public @java.lang.SuppressWarnings("all") String getFoo() { - return this.foo; - } } class Getter18 { @lombok.Getter String foo; diff --git a/test/transform/resource/after-ecj/GetterBoolean.java b/test/transform/resource/after-ecj/GetterBoolean.java index caf758c1..e9e4f370 100644 --- a/test/transform/resource/after-ecj/GetterBoolean.java +++ b/test/transform/resource/after-ecj/GetterBoolean.java @@ -2,9 +2,6 @@ class Getter { @lombok.Getter boolean foo; @lombok.Getter boolean isBar; @lombok.Getter boolean hasBaz; - Getter() { - super(); - } public @java.lang.SuppressWarnings("all") boolean isFoo() { return this.foo; } @@ -14,6 +11,9 @@ class Getter { public @java.lang.SuppressWarnings("all") boolean hasBaz() { return this.hasBaz; } + Getter() { + super(); + } } class MoreGetter { @lombok.Getter boolean foo; diff --git a/test/transform/resource/after-ecj/GetterOnClass.java b/test/transform/resource/after-ecj/GetterOnClass.java index 7668c9d3..421aa150 100644 --- a/test/transform/resource/after-ecj/GetterOnClass.java +++ b/test/transform/resource/after-ecj/GetterOnClass.java @@ -1,67 +1,68 @@ @lombok.Getter class GetterOnClass1 { @lombok.Getter(lombok.AccessLevel.NONE) boolean isNone; boolean isPublic; - GetterOnClass1() { - super(); - } public @java.lang.SuppressWarnings("all") boolean isPublic() { return this.isPublic; } + GetterOnClass1() { + super(); + } + } @lombok.Getter(lombok.AccessLevel.PROTECTED) class GetterOnClass2 { @lombok.Getter(lombok.AccessLevel.NONE) boolean isNone; boolean isProtected; @lombok.Getter(lombok.AccessLevel.PACKAGE) boolean isPackage; - GetterOnClass2() { - super(); - } @java.lang.SuppressWarnings("all") boolean isPackage() { return this.isPackage; } protected @java.lang.SuppressWarnings("all") boolean isProtected() { return this.isProtected; } + GetterOnClass2() { + super(); + } } @lombok.Getter(lombok.AccessLevel.PACKAGE) class GetterOnClass3 { @lombok.Getter(lombok.AccessLevel.NONE) boolean isNone; boolean isPackage; - GetterOnClass3() { - super(); - } @java.lang.SuppressWarnings("all") boolean isPackage() { return this.isPackage; } + GetterOnClass3() { + super(); + } } @lombok.Getter(lombok.AccessLevel.PRIVATE) class GetterOnClass4 { @lombok.Getter(lombok.AccessLevel.NONE) boolean isNone; boolean isPrivate; - GetterOnClass4() { - super(); - } private @java.lang.SuppressWarnings("all") boolean isPrivate() { return this.isPrivate; } + GetterOnClass4() { + super(); + } } @lombok.Getter(lombok.AccessLevel.PUBLIC) class GetterOnClass5 { @lombok.Getter(lombok.AccessLevel.NONE) boolean isNone; boolean isPublic; - GetterOnClass5() { - super(); - } public @java.lang.SuppressWarnings("all") boolean isPublic() { return this.isPublic; } + GetterOnClass5() { + super(); + } } @lombok.Getter class GetterOnClass6 { String couldBeNull; @lombok.NonNull String nonNull; - GetterOnClass6() { - super(); - } public @java.lang.SuppressWarnings("all") String getCouldBeNull() { return this.couldBeNull; } public @lombok.NonNull @java.lang.SuppressWarnings("all") String getNonNull() { return this.nonNull; } -} + GetterOnClass6() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/GetterOnStatic.java b/test/transform/resource/after-ecj/GetterOnStatic.java index ee90b897..538f25cb 100644 --- a/test/transform/resource/after-ecj/GetterOnStatic.java +++ b/test/transform/resource/after-ecj/GetterOnStatic.java @@ -3,13 +3,13 @@ class Getter { static @lombok.Getter int bar; <clinit>() { } - Getter() { - super(); - } public static @java.lang.SuppressWarnings("all") boolean isFoo() { return Getter.foo; } public static @java.lang.SuppressWarnings("all") int getBar() { return Getter.bar; } + Getter() { + super(); + } } diff --git a/test/transform/resource/after-ecj/GetterPlain.java b/test/transform/resource/after-ecj/GetterPlain.java index 19e24c77..cd096ca3 100644 --- a/test/transform/resource/after-ecj/GetterPlain.java +++ b/test/transform/resource/after-ecj/GetterPlain.java @@ -2,13 +2,13 @@ import lombok.Getter; class GetterPlain { @lombok.Getter int i; @Getter int foo; - GetterPlain() { - super(); - } public @java.lang.SuppressWarnings("all") int getI() { return this.i; } public @java.lang.SuppressWarnings("all") int getFoo() { return this.foo; } + GetterPlain() { + super(); + } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/GetterWithDollar.java b/test/transform/resource/after-ecj/GetterWithDollar.java index f4bc799c..b102ba66 100644 --- a/test/transform/resource/after-ecj/GetterWithDollar.java +++ b/test/transform/resource/after-ecj/GetterWithDollar.java @@ -1,22 +1,22 @@ class GetterWithDollar1 { @lombok.Getter int $i; - GetterWithDollar1() { - super(); - } public @java.lang.SuppressWarnings("all") int get$i() { return this.$i; } + GetterWithDollar1() { + super(); + } } class GetterWithDollar2 { @lombok.Getter int $i; @lombok.Getter int i; - GetterWithDollar2() { - super(); - } public @java.lang.SuppressWarnings("all") int get$i() { return this.$i; } public @java.lang.SuppressWarnings("all") int getI() { return this.i; } + GetterWithDollar2() { + super(); + } } diff --git a/test/transform/resource/after-ecj/LoggerCommons.java b/test/transform/resource/after-ecj/LoggerCommons.java new file mode 100644 index 00000000..bb38983f --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerCommons.java @@ -0,0 +1,24 @@ +@lombok.extern.apachecommons.Log class LoggerCommons { + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LoggerCommons.class); + <clinit>() { + } + LoggerCommons() { + super(); + } +} +@lombok.extern.apachecommons.Log(String.class) class LoggerCommonsString { + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(String.class); + <clinit>() { + } + LoggerCommonsString() { + super(); + } +} +@lombok.extern.apachecommons.Log(java.lang.String.class) class LoggerCommonsJavaLangString { + private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(java.lang.String.class); + <clinit>() { + } + LoggerCommonsJavaLangString() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerJul.java b/test/transform/resource/after-ecj/LoggerJul.java new file mode 100644 index 00000000..3d09cb71 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerJul.java @@ -0,0 +1,24 @@ +@lombok.extern.jul.Log class LoggerJul { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggerJul.class.getName()); + <clinit>() { + } + LoggerJul() { + super(); + } +} +@lombok.extern.jul.Log(String.class) class LoggerJulString { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(String.class.getName()); + <clinit>() { + } + LoggerJulString() { + super(); + } +} +@lombok.extern.jul.Log(java.lang.String.class) class LoggerJulJavaLangString { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(java.lang.String.class.getName()); + <clinit>() { + } + LoggerJulJavaLangString() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerLog4j.java b/test/transform/resource/after-ecj/LoggerLog4j.java new file mode 100644 index 00000000..45898a57 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerLog4j.java @@ -0,0 +1,24 @@ +@lombok.extern.log4j.Log class LoggerLog4j { + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LoggerLog4j.class); + <clinit>() { + } + LoggerLog4j() { + super(); + } +} +@lombok.extern.log4j.Log(String.class) class LoggerLog4jString { + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(String.class); + <clinit>() { + } + LoggerLog4jString() { + super(); + } +} +@lombok.extern.log4j.Log(java.lang.String.class) class LoggerLog4jJavaLangString { + private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(java.lang.String.class); + <clinit>() { + } + LoggerLog4jJavaLangString() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4j.java b/test/transform/resource/after-ecj/LoggerSlf4j.java new file mode 100644 index 00000000..e635ece8 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4j.java @@ -0,0 +1,21 @@ +@lombok.extern.slf4j.Log class LoggerSlf4j { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4j.class); + <clinit>() { + } + LoggerSlf4j() { + super(); + } +} +class LoggerSlf4jOuter { + static @lombok.extern.slf4j.Log class Inner { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Inner.class); + <clinit>() { + } + Inner() { + super(); + } + } + LoggerSlf4jOuter() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4jAlreadyExists.java b/test/transform/resource/after-ecj/LoggerSlf4jAlreadyExists.java new file mode 100644 index 00000000..22fa0eeb --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jAlreadyExists.java @@ -0,0 +1,6 @@ +@lombok.extern.slf4j.Log class LoggerSlf4jAlreadyExists { + int log; + LoggerSlf4jAlreadyExists() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4jClassOfArray.java b/test/transform/resource/after-ecj/LoggerSlf4jClassOfArray.java new file mode 100644 index 00000000..20fe0fde --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jClassOfArray.java @@ -0,0 +1,16 @@ +@lombok.extern.slf4j.Log(String[].class) class LoggerSlf4jClassOfArray { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(String[].class); + <clinit>() { + } + LoggerSlf4jClassOfArray() { + super(); + } +} +@lombok.extern.slf4j.Log(java.lang.String[].class) class LoggerSlf4jClassOfArrayJLS { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.lang.String[].class); + <clinit>() { + } + LoggerSlf4jClassOfArrayJLS() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4jOnNonType.java b/test/transform/resource/after-ecj/LoggerSlf4jOnNonType.java new file mode 100644 index 00000000..a45612ae --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jOnNonType.java @@ -0,0 +1,7 @@ +class LoggerSlf4jOnNonType { + LoggerSlf4jOnNonType() { + super(); + } + @lombok.extern.slf4j.Log void foo() { + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4jTypes.java b/test/transform/resource/after-ecj/LoggerSlf4jTypes.java new file mode 100644 index 00000000..25b3fd86 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jTypes.java @@ -0,0 +1,31 @@ +@lombok.extern.slf4j.Log interface LoggerSlf4jTypesInterface { +} +@lombok.extern.slf4j.Log @interface LoggerSlf4jTypesAnnotation { +} +@lombok.extern.slf4j.Log enum LoggerSlf4jTypesEnum { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnum.class); + <clinit>() { + } + LoggerSlf4jTypesEnum() { + super(); + } +} +@lombok.extern.slf4j.Log enum LoggerSlf4jTypesEnumWithElement { + FOO(), + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnumWithElement.class); + <clinit>() { + } + LoggerSlf4jTypesEnumWithElement() { + super(); + } +} +interface LoggerSlf4jTypesInterfaceOuter { + @lombok.extern.slf4j.Log class Inner { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Inner.class); + <clinit>() { + } + Inner() { + super(); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerSlf4jWithClass.java b/test/transform/resource/after-ecj/LoggerSlf4jWithClass.java new file mode 100644 index 00000000..9f4846aa --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jWithClass.java @@ -0,0 +1,32 @@ +@lombok.extern.slf4j.Log(String.class) class LoggerSlf4jWithClass { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(String.class); + <clinit>() { + } + LoggerSlf4jWithClass() { + super(); + } +} +@lombok.extern.slf4j.Log(java.util.List.class) class LoggerSlf4jWithClassList { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.util.List.class); + <clinit>() { + } + LoggerSlf4jWithClassList() { + super(); + } +} +@lombok.extern.slf4j.Log(value = java.lang.String.class) class LoggerSlf4jWithClassValue { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.lang.String.class); + <clinit>() { + } + LoggerSlf4jWithClassValue() { + super(); + } +} +@lombok.extern.slf4j.Log(void.class) class LoggerSlf4jWithClassVoid { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(void.class); + <clinit>() { + } + LoggerSlf4jWithClassVoid() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/LoggerSlf4jWithPackage.java b/test/transform/resource/after-ecj/LoggerSlf4jWithPackage.java new file mode 100644 index 00000000..655d14f8 --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerSlf4jWithPackage.java @@ -0,0 +1,22 @@ +package before; +@lombok.extern.slf4j.Log class LoggerSlf4jWithPackage { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jWithPackage.class); + <clinit>() { + } + LoggerSlf4jWithPackage() { + super(); + } +} +class LoggerSlf4jWithPackageOuter { + static @lombok.extern.slf4j.Log class Inner { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Inner.class); + <clinit>() { + } + Inner() { + super(); + } + } + LoggerSlf4jWithPackageOuter() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/MultiFieldGetter.java b/test/transform/resource/after-ecj/MultiFieldGetter.java index 4ed6038d..16368f25 100644 --- a/test/transform/resource/after-ecj/MultiFieldGetter.java +++ b/test/transform/resource/after-ecj/MultiFieldGetter.java @@ -3,26 +3,26 @@ import lombok.AccessLevel; class MultiFieldGetter { @Getter(AccessLevel.PROTECTED) int x; @Getter(AccessLevel.PROTECTED) int y; - MultiFieldGetter() { - super(); - } protected @java.lang.SuppressWarnings("all") int getX() { return this.x; } protected @java.lang.SuppressWarnings("all") int getY() { return this.y; } + MultiFieldGetter() { + super(); + } } @Getter class MultiFieldGetter2 { @Getter(AccessLevel.PACKAGE) int x; @Getter(AccessLevel.PACKAGE) int y; - MultiFieldGetter2() { - super(); - } @java.lang.SuppressWarnings("all") int getX() { return this.x; } @java.lang.SuppressWarnings("all") int getY() { return this.y; } + MultiFieldGetter2() { + super(); + } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/NonNullPlain.java b/test/transform/resource/after-ecj/NonNullPlain.java index 877f97ae..6f552436 100644 --- a/test/transform/resource/after-ecj/NonNullPlain.java +++ b/test/transform/resource/after-ecj/NonNullPlain.java @@ -1,9 +1,6 @@ class NonNullPlain { @lombok.Setter @lombok.NonNull @lombok.Getter int i; @lombok.Getter @lombok.Setter @lombok.NonNull String s; - NonNullPlain() { - super(); - } public @java.lang.SuppressWarnings("all") void setI(final @lombok.NonNull int i) { this.i = i; } @@ -18,4 +15,7 @@ class NonNullPlain { throw new java.lang.NullPointerException("s"); this.s = s; } + NonNullPlain() { + super(); + } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/SetterAccessLevel.java b/test/transform/resource/after-ecj/SetterAccessLevel.java index 20eb9d2c..deee8213 100644 --- a/test/transform/resource/after-ecj/SetterAccessLevel.java +++ b/test/transform/resource/after-ecj/SetterAccessLevel.java @@ -5,9 +5,6 @@ class SetterAccessLevel { @lombok.Setter(lombok.AccessLevel.PROTECTED) boolean isProtected; @lombok.Setter(lombok.AccessLevel.PUBLIC) boolean isPublic; @lombok.Setter(value = lombok.AccessLevel.PUBLIC) boolean value; - SetterAccessLevel() { - super(); - } private @java.lang.SuppressWarnings("all") void setIsPrivate(final boolean isPrivate) { this.isPrivate = isPrivate; } @@ -23,4 +20,7 @@ class SetterAccessLevel { public @java.lang.SuppressWarnings("all") void setValue(final boolean value) { this.value = value; } + SetterAccessLevel() { + super(); + } } diff --git a/test/transform/resource/after-ecj/SetterOnClass.java b/test/transform/resource/after-ecj/SetterOnClass.java index e92e217c..084323c4 100644 --- a/test/transform/resource/after-ecj/SetterOnClass.java +++ b/test/transform/resource/after-ecj/SetterOnClass.java @@ -1,63 +1,60 @@ @lombok.Setter class SetterOnClass1 { @lombok.Setter(lombok.AccessLevel.NONE) boolean isNone; boolean isPublic; - SetterOnClass1() { - super(); - } public @java.lang.SuppressWarnings("all") void setIsPublic(final boolean isPublic) { this.isPublic = isPublic; } + SetterOnClass1() { + super(); + } } @lombok.Setter(lombok.AccessLevel.PROTECTED) class SetterOnClass2 { @lombok.Setter(lombok.AccessLevel.NONE) boolean isNone; boolean isProtected; @lombok.Setter(lombok.AccessLevel.PACKAGE) boolean isPackage; - SetterOnClass2() { - super(); - } @java.lang.SuppressWarnings("all") void setIsPackage(final boolean isPackage) { this.isPackage = isPackage; } protected @java.lang.SuppressWarnings("all") void setIsProtected(final boolean isProtected) { this.isProtected = isProtected; } + SetterOnClass2() { + super(); + } } @lombok.Setter(lombok.AccessLevel.PACKAGE) class SetterOnClass3 { @lombok.Setter(lombok.AccessLevel.NONE) boolean isNone; boolean isPackage; - SetterOnClass3() { - super(); - } @java.lang.SuppressWarnings("all") void setIsPackage(final boolean isPackage) { this.isPackage = isPackage; } + SetterOnClass3() { + super(); + } } @lombok.Setter(lombok.AccessLevel.PRIVATE) class SetterOnClass4 { @lombok.Setter(lombok.AccessLevel.NONE) boolean isNone; boolean isPrivate; - SetterOnClass4() { - super(); - } private @java.lang.SuppressWarnings("all") void setIsPrivate(final boolean isPrivate) { this.isPrivate = isPrivate; } + SetterOnClass4() { + super(); + } } @lombok.Setter(lombok.AccessLevel.PUBLIC) class SetterOnClass5 { @lombok.Setter(lombok.AccessLevel.NONE) boolean isNone; boolean isPublic; - SetterOnClass5() { - super(); - } public @java.lang.SuppressWarnings("all") void setIsPublic(final boolean isPublic) { this.isPublic = isPublic; } + SetterOnClass5() { + super(); + } } @lombok.Setter class SetterOnClass6 { String couldBeNull; @lombok.NonNull String nonNull; - SetterOnClass6() { - super(); - } public @java.lang.SuppressWarnings("all") void setCouldBeNull(final String couldBeNull) { this.couldBeNull = couldBeNull; } @@ -66,4 +63,7 @@ throw new java.lang.NullPointerException("nonNull"); this.nonNull = nonNull; } + SetterOnClass6() { + super(); + } } diff --git a/test/transform/resource/after-ecj/SetterOnStatic.java b/test/transform/resource/after-ecj/SetterOnStatic.java index 8a5abdd8..c1e4d3d1 100644 --- a/test/transform/resource/after-ecj/SetterOnStatic.java +++ b/test/transform/resource/after-ecj/SetterOnStatic.java @@ -3,13 +3,13 @@ class Setter { static @lombok.Setter int bar; <clinit>() { } - Setter() { - super(); - } public static @java.lang.SuppressWarnings("all") void setFoo(final boolean foo) { Setter.foo = foo; } public static @java.lang.SuppressWarnings("all") void setBar(final int bar) { Setter.bar = bar; } + Setter() { + super(); + } } diff --git a/test/transform/resource/after-ecj/SetterPlain.java b/test/transform/resource/after-ecj/SetterPlain.java index 7f0a4a81..08154244 100644 --- a/test/transform/resource/after-ecj/SetterPlain.java +++ b/test/transform/resource/after-ecj/SetterPlain.java @@ -2,13 +2,13 @@ import lombok.Setter; class SetterPlain { @lombok.Setter int i; @Setter int foo; - SetterPlain() { - super(); - } public @java.lang.SuppressWarnings("all") void setI(final int i) { this.i = i; } public @java.lang.SuppressWarnings("all") void setFoo(final int foo) { this.foo = foo; } + SetterPlain() { + super(); + } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/SetterWithDollar.java b/test/transform/resource/after-ecj/SetterWithDollar.java index c5bc14f1..bf27536b 100644 --- a/test/transform/resource/after-ecj/SetterWithDollar.java +++ b/test/transform/resource/after-ecj/SetterWithDollar.java @@ -1,22 +1,22 @@ class SetterWithDollar1 { @lombok.Setter int $i; - SetterWithDollar1() { - super(); - } public @java.lang.SuppressWarnings("all") void set$i(final int $i) { this.$i = $i; } + SetterWithDollar1() { + super(); + } } class SetterWithDollar2 { @lombok.Setter int $i; @lombok.Setter int i; - SetterWithDollar2() { - super(); - } public @java.lang.SuppressWarnings("all") void set$i(final int $i) { this.$i = $i; } public @java.lang.SuppressWarnings("all") void setI(final int i) { this.i = i; } + SetterWithDollar2() { + super(); + } } diff --git a/test/transform/resource/after-ecj/SynchronizedPlain.java b/test/transform/resource/after-ecj/SynchronizedPlain.java index b9f032c5..8e5b6297 100644 --- a/test/transform/resource/after-ecj/SynchronizedPlain.java +++ b/test/transform/resource/after-ecj/SynchronizedPlain.java @@ -19,6 +19,8 @@ class SynchronizedPlain1 { } class SynchronizedPlain2 { private static final @java.lang.SuppressWarnings("all") java.lang.Object $LOCK = new java.lang.Object[0]; + <clinit>() { + } SynchronizedPlain2() { super(); } diff --git a/test/transform/resource/after-ecj/ToStringInner.java b/test/transform/resource/after-ecj/ToStringInner.java index 2f14407e..963299db 100644 --- a/test/transform/resource/after-ecj/ToStringInner.java +++ b/test/transform/resource/after-ecj/ToStringInner.java @@ -2,31 +2,31 @@ import lombok.ToString; @ToString class ToStringOuter { @ToString class ToStringInner { final int y; - ToStringInner() { - super(); - } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (("ToStringOuter.ToStringInner(y=" + this.y) + ")"); } + ToStringInner() { + super(); + } } static @ToString class ToStringStaticInner { final int y; - ToStringStaticInner() { - super(); - } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (("ToStringOuter.ToStringStaticInner(y=" + this.y) + ")"); } + ToStringStaticInner() { + super(); + } } class ToStringMiddle { @ToString class ToStringMoreInner { final String name; - ToStringMoreInner() { - super(); - } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (("ToStringOuter.ToStringMiddle.ToStringMoreInner(name=" + this.name) + ")"); } + ToStringMoreInner() { + super(); + } } ToStringMiddle() { super(); @@ -34,10 +34,10 @@ import lombok.ToString; } final int x; String name; - ToStringOuter() { - super(); - } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (((("ToStringOuter(x=" + this.x) + ", name=") + this.name) + ")"); } + ToStringOuter() { + super(); + } } diff --git a/test/transform/resource/after-ecj/ToStringPlain.java b/test/transform/resource/after-ecj/ToStringPlain.java index 7196abb9..458f78d0 100644 --- a/test/transform/resource/after-ecj/ToStringPlain.java +++ b/test/transform/resource/after-ecj/ToStringPlain.java @@ -2,20 +2,20 @@ import lombok.ToString; @lombok.ToString class ToString1 { final int x; String name; - ToString1() { - super(); - } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (((("ToString1(x=" + this.x) + ", name=") + this.name) + ")"); } + ToString1() { + super(); + } } @ToString class ToString2 { final int x; String name; - ToString2() { - super(); - } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (((("ToString2(x=" + this.x) + ", name=") + this.name) + ")"); } + ToString2() { + super(); + } } diff --git a/test/transform/resource/before/DataPlain.java b/test/transform/resource/before/DataPlain.java index 680ae46f..4151dd20 100644 --- a/test/transform/resource/before/DataPlain.java +++ b/test/transform/resource/before/DataPlain.java @@ -6,4 +6,16 @@ import lombok.Data; @Data class Data2 { final int x; String name; -}
\ No newline at end of file +} +final @Data class Data3 { + final int x; + String name; +} +@Data +@lombok.EqualsAndHashCode(callSuper=true) +final class Data4 extends java.util.Timer { + final int x; + Data4() { + super(); + } +} diff --git a/test/transform/resource/before/LoggerCommons.java b/test/transform/resource/before/LoggerCommons.java new file mode 100644 index 00000000..d6359bd7 --- /dev/null +++ b/test/transform/resource/before/LoggerCommons.java @@ -0,0 +1,11 @@ +@lombok.extern.apachecommons.Log +class LoggerCommons { +} + +@lombok.extern.apachecommons.Log(String.class) +class LoggerCommonsString { +} + +@lombok.extern.apachecommons.Log(java.lang.String.class) +class LoggerCommonsJavaLangString { +}
\ No newline at end of file diff --git a/test/transform/resource/before/LoggerJul.java b/test/transform/resource/before/LoggerJul.java new file mode 100644 index 00000000..1c74ea4f --- /dev/null +++ b/test/transform/resource/before/LoggerJul.java @@ -0,0 +1,11 @@ +@lombok.extern.jul.Log +class LoggerJul { +} + +@lombok.extern.jul.Log(String.class) +class LoggerJulString { +} + +@lombok.extern.jul.Log(java.lang.String.class) +class LoggerJulJavaLangString { +}
\ No newline at end of file diff --git a/test/transform/resource/before/LoggerLog4j.java b/test/transform/resource/before/LoggerLog4j.java new file mode 100644 index 00000000..0199809c --- /dev/null +++ b/test/transform/resource/before/LoggerLog4j.java @@ -0,0 +1,11 @@ +@lombok.extern.log4j.Log +class LoggerLog4j { +} + +@lombok.extern.log4j.Log(String.class) +class LoggerLog4jString { +} + +@lombok.extern.log4j.Log(java.lang.String.class) +class LoggerLog4jJavaLangString { +}
\ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4j.java b/test/transform/resource/before/LoggerSlf4j.java new file mode 100644 index 00000000..92aeefbd --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4j.java @@ -0,0 +1,9 @@ +@lombok.extern.slf4j.Log +class LoggerSlf4j { +} +class LoggerSlf4jOuter { + @lombok.extern.slf4j.Log + static class Inner { + + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4jAlreadyExists.java b/test/transform/resource/before/LoggerSlf4jAlreadyExists.java new file mode 100644 index 00000000..8ac0225d --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jAlreadyExists.java @@ -0,0 +1,4 @@ +@lombok.extern.slf4j.Log +class LoggerSlf4jAlreadyExists { + int log; +}
\ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4jClassOfArray.java b/test/transform/resource/before/LoggerSlf4jClassOfArray.java new file mode 100644 index 00000000..87248538 --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jClassOfArray.java @@ -0,0 +1,6 @@ +@lombok.extern.slf4j.Log(String[].class) +class LoggerSlf4jClassOfArray { +} +@lombok.extern.slf4j.Log(java.lang.String[].class) +class LoggerSlf4jClassOfArrayJLS { +} diff --git a/test/transform/resource/before/LoggerSlf4jOnNonType.java b/test/transform/resource/before/LoggerSlf4jOnNonType.java new file mode 100644 index 00000000..c57e171c --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jOnNonType.java @@ -0,0 +1,5 @@ +class LoggerSlf4jOnNonType { + @lombok.extern.slf4j.Log + void foo() { + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4jTypes.java b/test/transform/resource/before/LoggerSlf4jTypes.java new file mode 100644 index 00000000..9f221f73 --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jTypes.java @@ -0,0 +1,18 @@ +@lombok.extern.slf4j.Log +interface LoggerSlf4jTypesInterface { +} +@lombok.extern.slf4j.Log +@interface LoggerSlf4jTypesAnnotation { +} +@lombok.extern.slf4j.Log +enum LoggerSlf4jTypesEnum { +} +@lombok.extern.slf4j.Log +enum LoggerSlf4jTypesEnumWithElement { + FOO; +} +interface LoggerSlf4jTypesInterfaceOuter { + @lombok.extern.slf4j.Log + class Inner { + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/LoggerSlf4jWithClass.java b/test/transform/resource/before/LoggerSlf4jWithClass.java new file mode 100644 index 00000000..b9cf8187 --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jWithClass.java @@ -0,0 +1,12 @@ +@lombok.extern.slf4j.Log(String.class) +class LoggerSlf4jWithClass { +} +@lombok.extern.slf4j.Log(java.util.List.class) +class LoggerSlf4jWithClassList { +} +@lombok.extern.slf4j.Log(value = java.lang.String.class) +class LoggerSlf4jWithClassValue { +} +@lombok.extern.slf4j.Log(void.class) +class LoggerSlf4jWithClassVoid { +} diff --git a/test/transform/resource/before/LoggerSlf4jWithPackage.java b/test/transform/resource/before/LoggerSlf4jWithPackage.java new file mode 100644 index 00000000..efbaef68 --- /dev/null +++ b/test/transform/resource/before/LoggerSlf4jWithPackage.java @@ -0,0 +1,9 @@ +package before; +@lombok.extern.slf4j.Log +class LoggerSlf4jWithPackage { +} +class LoggerSlf4jWithPackageOuter { + @lombok.extern.slf4j.Log + static class Inner { + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValComplex.java b/test/transform/resource/before/ValComplex.java new file mode 100644 index 00000000..5f718003 --- /dev/null +++ b/test/transform/resource/before/ValComplex.java @@ -0,0 +1,20 @@ +public class ValComplex { + private ValSimple field = new ValSimple(); + private static final int CONSTANT = 20; + + public void testReferencingOtherFiles() { + val shouldBeString = field.method(); + val shouldBeInt = CONSTANT; + val lock = new Object(); + synchronized (lock) { + val field = 20; //Shadowing + val inner = 10; + switch (field) { + case 5: + val shouldBeString2 = shouldBeString; + val innerInner = inner; + } + } + val shouldBeValSimple = field; //Unshadowing + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValErrors.java b/test/transform/resource/before/ValErrors.java new file mode 100644 index 00000000..742bca6d --- /dev/null +++ b/test/transform/resource/before/ValErrors.java @@ -0,0 +1,9 @@ +public class ValErrors { + public void nullType() { + val a = null; + } + + public void unresolvableExpression() { + val c = d; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValInFor.java b/test/transform/resource/before/ValInFor.java new file mode 100644 index 00000000..af13540e --- /dev/null +++ b/test/transform/resource/before/ValInFor.java @@ -0,0 +1,20 @@ +public class ValInFor { + { + val x = 10; + val x2 = -1; + val a = "Hello"; + for (val y = x, z = x2; y < 20; y++) { + val q = y; + val w = z; + val v = a; + } + } + +/* public void enhancedFor() { + java.util.List<String> list = java.util.Arrays.asList("Hello, World!"); + for (val shouldBeString : list) { + System.out.println(shouldBeString.toLowerCase()); + val shouldBeString2 = shouldBeString; + } + }*/ +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValLessSimple.java b/test/transform/resource/before/ValLessSimple.java new file mode 100644 index 00000000..bae7b73b --- /dev/null +++ b/test/transform/resource/before/ValLessSimple.java @@ -0,0 +1,31 @@ +public class ValLessSimple { + private short field2 = 5; + + private String method() { + return "method"; + } + + private double method2() { + return 2.0; + } + + { + System.out.println("Hello"); + val z = 20; + val x = 10; + val a = z; + val y = field2; + } + + private void testVal(String param) { + val fieldV = field; + val a = 10; + val b = 20; + { + val methodV = method(); + val foo = fieldV + methodV; + } + } + + private String field = "field"; +} diff --git a/test/transform/resource/before/ValSimple.java b/test/transform/resource/before/ValSimple.java new file mode 100644 index 00000000..15508bbc --- /dev/null +++ b/test/transform/resource/before/ValSimple.java @@ -0,0 +1,26 @@ +public class ValSimple { + private String field = "field"; + private short field2 = 5; + + private String method() { + return "method"; + } + + private double method2() { + return 2.0; + } + + private void testVal(String param) { + val fieldV = field; + val methodV = method(); + val paramV = param; + + val valOfVal = fieldV; + val operatorV = fieldV + valOfVal; + + val fieldW = field2; + val methodW = method2(); + byte localVar = 3; + val operatorW = fieldW + localVar; + } +} diff --git a/test/transform/resource/before/ValWeirdTypes.java b/test/transform/resource/before/ValWeirdTypes.java new file mode 100644 index 00000000..6f6eb9db --- /dev/null +++ b/test/transform/resource/before/ValWeirdTypes.java @@ -0,0 +1,54 @@ +import java.util.*; + +public class ValWeirdTypes<Z> { + private final List<Z> fieldList; + + public void testGenerics() { + List<String> list = new ArrayList<String>(); + list.add("Hello, World!"); + val shouldBeString = list.get(0); + val shouldBeListOfString = list; + val shouldBeListOfStringToo = Arrays.asList("hello", "world"); + val shouldBeString2 = shouldBeListOfString.get(0); + } + + public void testGenericsInference() { + val huh = Collections.emptyList(); + val huh2 = Collections.<Number>emptyList(); + } + + public void testPrimitives() { + val x = 10; + val y = 5 + 3L; + } + + public void testAnonymousInnerClass() { + val y = new Runnable() { + public void run() {} + }; + } + + public <T extends Number> void testTypeParams(List<T> param) { + val t = param.get(0); + val z = fieldList.get(0); + val k = param; + val y = fieldList; + } + + public void testBounds(List<? extends Number> lower, List<? super Number> upper) { + val a = lower.get(0); + val b = upper.get(0); + val c = lower; + val d = upper; + List<?> unbound = lower; + val e = unbound; + } + + public void testCompound() { + val a = new ArrayList<String>(); + val b = new Vector<String>(); + val c = 1 < System.currentTimeMillis(); + val d = c ? a : b; + java.util.RandomAccess confirm = c ? a : b; + } +}
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/LoggerSlf4jAlreadyExists.java.messages b/test/transform/resource/messages-delombok/LoggerSlf4jAlreadyExists.java.messages new file mode 100644 index 00000000..ede6defa --- /dev/null +++ b/test/transform/resource/messages-delombok/LoggerSlf4jAlreadyExists.java.messages @@ -0,0 +1 @@ +1:1 WARNING Field 'log' already exists. diff --git a/test/transform/resource/messages-delombok/LoggerSlf4jOnNonStaticInnerClass.java.messages b/test/transform/resource/messages-delombok/LoggerSlf4jOnNonStaticInnerClass.java.messages new file mode 100644 index 00000000..e0bbdb2a --- /dev/null +++ b/test/transform/resource/messages-delombok/LoggerSlf4jOnNonStaticInnerClass.java.messages @@ -0,0 +1 @@ +2:9 ERROR @Log is not legal on non-static inner classes.
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/LoggerSlf4jOnNonType.java.messages b/test/transform/resource/messages-delombok/LoggerSlf4jOnNonType.java.messages new file mode 100644 index 00000000..9143d4bc --- /dev/null +++ b/test/transform/resource/messages-delombok/LoggerSlf4jOnNonType.java.messages @@ -0,0 +1 @@ +2:9 ERROR @Log is legal only on types.
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/LoggerSlf4jTypes.java.messages b/test/transform/resource/messages-delombok/LoggerSlf4jTypes.java.messages new file mode 100644 index 00000000..ba97e38f --- /dev/null +++ b/test/transform/resource/messages-delombok/LoggerSlf4jTypes.java.messages @@ -0,0 +1,2 @@ +1:1 ERROR @Log is legal only on classes and enums. +4:1 ERROR @Log is legal only on classes and enums.
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/ValErrors.java.messages b/test/transform/resource/messages-delombok/ValErrors.java.messages new file mode 100644 index 00000000..feba6912 --- /dev/null +++ b/test/transform/resource/messages-delombok/ValErrors.java.messages @@ -0,0 +1,2 @@ +3:21 ERROR Cannot use 'val' here because initializer expression does not have a representable type: <nulltype> +7:21 ERROR Cannot use 'val' here because initializer expression does not have a representable type: Type cannot be resolved diff --git a/test/transform/resource/messages-ecj/LoggerSlf4jAlreadyExists.java.messages b/test/transform/resource/messages-ecj/LoggerSlf4jAlreadyExists.java.messages new file mode 100644 index 00000000..f03c7660 --- /dev/null +++ b/test/transform/resource/messages-ecj/LoggerSlf4jAlreadyExists.java.messages @@ -0,0 +1 @@ +1 warning Field 'log' already exists. diff --git a/test/transform/resource/messages-ecj/LoggerSlf4jOnNonStaticInnerClass.java.messages b/test/transform/resource/messages-ecj/LoggerSlf4jOnNonStaticInnerClass.java.messages new file mode 100644 index 00000000..e0bbdb2a --- /dev/null +++ b/test/transform/resource/messages-ecj/LoggerSlf4jOnNonStaticInnerClass.java.messages @@ -0,0 +1 @@ +2:9 ERROR @Log is not legal on non-static inner classes.
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/LoggerSlf4jOnNonType.java.messages b/test/transform/resource/messages-ecj/LoggerSlf4jOnNonType.java.messages new file mode 100644 index 00000000..4a446f28 --- /dev/null +++ b/test/transform/resource/messages-ecj/LoggerSlf4jOnNonType.java.messages @@ -0,0 +1 @@ +2 error @Log is legal only on types.
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/LoggerSlf4jTypes.java.messages b/test/transform/resource/messages-ecj/LoggerSlf4jTypes.java.messages new file mode 100644 index 00000000..42236c7c --- /dev/null +++ b/test/transform/resource/messages-ecj/LoggerSlf4jTypes.java.messages @@ -0,0 +1,2 @@ +1 error @Log is legal only on classes and enums. +4 error @Log is legal only on classes and enums.
\ No newline at end of file diff --git a/usage_examples/LogExample_post.jpage b/usage_examples/LogExample_post.jpage new file mode 100644 index 00000000..cbdc5a9e --- /dev/null +++ b/usage_examples/LogExample_post.jpage @@ -0,0 +1,15 @@ +public class LogExample { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class); + + public static void main(String... args) { + log.error("Something's wrong here"); + } +} + +public class LogExampleOther { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(java.util.List.class); + + public static void main(String... args) { + log.warn("Something might be wrong here"); + } +} diff --git a/usage_examples/LogExample_pre.jpage b/usage_examples/LogExample_pre.jpage new file mode 100644 index 00000000..7ab64cd4 --- /dev/null +++ b/usage_examples/LogExample_pre.jpage @@ -0,0 +1,17 @@ +import lombok.extern.slf4j.Log; + +@Log +public class LogExample { + + public static void main(String... args) { + log.error("Something's wrong here"); + } +} + +@Log(java.util.List.class) +public class LogExampleOther { + + public static void main(String... args) { + log.warn("Something might be wrong here"); + } +} diff --git a/website/features/Log.html b/website/features/Log.html new file mode 100644 index 00000000..6912b6ed --- /dev/null +++ b/website/features/Log.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<html><head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="stylesheet" type="text/css" href="../logi/reset.css" /> + <link rel="stylesheet" type="text/css" href="features.css" /> + <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" /> + <meta name="description" content="Spice up your java" /> + <title>@Log</title> +</head><body><div id="pepper"> + <div class="minimumHeight"></div> + <div class="meat"> + <div class="header"><a href="../index.html">Project Lombok</a></div> + <h1>@Log</h1> + <div class="byline">Captain's Log, stardate 24435.7: "What was that line again?"</div> + <div class="overview"> + <h3>Overview</h3> + <p> + You can annotate any field with <code>@Log</code> to let lombok generate a logger field automatically.<br /> + The logger is named <code>log</code> and field's type depends on which logger you have selected. + </p><p> + There are four <code>@Log</code> choices available:<br /> + <dl> + <dt><code>@lombok.extern.apachecommons.Log</code></dt> + <dd>Creates <code><span class="keyword">private static final </span><a href="http://commons.apache.org/logging/apidocs/org/apache/commons/logging/Log.html">org.apache.commons.logging.Log</a> <span class="staticfield">log</span> = <a href="http://commons.apache.org/logging/apidocs/org/apache/commons/logging/LogFactory.html#getLog(java.lang.Class)">org.apache.commons.logging.LogFactory.getLog</a>(LogExample.<span class="keyword">class</span>);</code></dd> + <dt><code>@lombok.extern.jul.Log</code></dt> + <dd>Creates <code><span class="keyword">private static final </span><a href="http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html">java.util.logging.Logger</a> <span class="staticfield">log</span> = <a href="http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html#getLogger(java.lang.String)">java.util.logging.Logger.getLogger</a>(LogExample.<span class="keyword">class</span>.getName());</code></dd> + <dt><code>@lombok.extern.log4j.Log</code></dt> + <dd>Creates <code><span class="keyword">private static final </span><a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Logger.html">org.apache.log4j.Logger</a> <span class="staticfield">log</span> = <a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Logger.html#getLogger(java.lang.Class)">org.apache.log4j.Logger.getLogger</a>(LogExample.<span class="keyword">class</span>);</code></dd> + <dt><code>@lombok.extern.slf4j.Log</code></dt> + <dd>Creates <code><span class="keyword">private static final </span><a href="http://www.slf4j.org/api/org/slf4j/Logger.html">org.slf4j.Logger</a> <span class="staticfield">log</span> = <a href="http://www.slf4j.org/apidocs/org/slf4j/LoggerFactory.html#getLogger(java.lang.Class)">org.slf4j.LoggerFactory.getLogger</a>(LogExample.<span class="keyword">class</span>);</code></dd> + </dl> + </p> + <p> + All <code>@Log</code> annotations can take an optional parameter of type <code>Class</code>. If such a parameter is specified, that class will be used as the parameter for the logger factory call. + </p> + </div> + <div class="snippets"> + <div class="pre"> + <h3>With Lombok</h3> + <div class="snippet">@HTML_PRE@</div> + </div> + <div class="sep"></div> + <div class="post"> + <h3>Vanilla Java</h3> + <div class="snippet">@HTML_POST@</div> + </div> + </div> + <div style="clear: left;"></div> + <div class="overview"> + <h3>Small print</h3><div class="smallprint"> + <p> + If a field called <code>log</code> already exists, a warning will be emitted and no code will be generated. + </p> + </div> + </div> + <div class="footer"> + <a href="index.html">Back to features</a> | <a href="SneakyThrows.html">Previous feature (@SneakyThrows)</a> | <span class="disabled">Next feature</span><br /> + <a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> + </div> + <div style="clear: both;"></div> + </div> +</div> +<script type="text/javascript"> + var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); + document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); +</script> +<script type="text/javascript"> + try { + var pageTracker = _gat._getTracker("UA-9884254-1"); + pageTracker._trackPageview(); + } catch(err) {} +</script> +</body></html> diff --git a/website/features/SneakyThrows.html b/website/features/SneakyThrows.html index ec7d09c5..0781f083 100644 --- a/website/features/SneakyThrows.html +++ b/website/features/SneakyThrows.html @@ -71,7 +71,7 @@ </div> </div> <div class="footer"> - <a href="index.html">Back to features</a> | <a href="Synchronized.html">Previous feature (@Synchronized)</a> | <span class="disabled">Next feature</span><br /> + <a href="index.html">Back to features</a> | <a href="Synchronized.html">Previous feature (@Synchronized)</a> | <a href="Log.html">Next feature (@Log)</a><br /> <a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009 Reinier Zwitserloot and Roel Spilker, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> </div> <div style="clear: both;"></div> diff --git a/website/features/features.css b/website/features/features.css index 5de41654..a7e8e318 100644 --- a/website/features/features.css +++ b/website/features/features.css @@ -64,6 +64,15 @@ h1 { margin-left: 32px; } +dt { + margin-top: 4px; + font-size: 1.2em; +} + +dd { + margin-left: 16px; +} + .overview code { font-size: 1.1em; } @@ -138,3 +147,23 @@ h1 { font-style: normal; font-weight: bold; } + +code a { + color: black; + text-decoration: none; +} + +code a:hover { + color: black; + text-decoration: underline; +} + +code .keyword { + color: #7f0055; + font-weight: bold; +} + +code .staticfield { + color: #2a00ff; + font-style: italic; +}
\ No newline at end of file diff --git a/website/features/index.html b/website/features/index.html index 869bbe89..d216ddb4 100644 --- a/website/features/index.html +++ b/website/features/index.html @@ -30,6 +30,8 @@ <dd><code>synchronized</code> done right: Don't expose your locks.</dd> <dt><a href="SneakyThrows.html"><code>@SneakyThrows</code></a></dt> <dd>To boldly throw checked exceptions where no one has thrown them before!</dd> + <dt><a href="Log.html"><code>@Log</code></a></dt> + <dd>Captain's Log, stardate 24435.7: "What was that line again?"</dd> </dl> </div> <div class="pointer"> |