diff options
Diffstat (limited to 'src/lombok')
44 files changed, 1947 insertions, 51 deletions
diff --git a/src/lombok/AccessLevel.java b/src/lombok/AccessLevel.java index 37b91235..973b3c18 100644 --- a/src/lombok/AccessLevel.java +++ b/src/lombok/AccessLevel.java @@ -1,5 +1,29 @@ +/* + * Copyright © 2009 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; +/** + * Represents an AccessLevel. Used e.g. to specify the access level for generated methods and fields. + */ public enum AccessLevel { PUBLIC, MODULE, PROTECTED, PACKAGE, PRIVATE; } diff --git a/src/lombok/Cleanup.java b/src/lombok/Cleanup.java index c847e942..4c3838f2 100644 --- a/src/lombok/Cleanup.java +++ b/src/lombok/Cleanup.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import java.lang.annotation.ElementType; @@ -5,8 +26,57 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Ensures the variable declaration that you annotate will be cleaned up by calling its close method, regardless + * of what happens. Implemented by wrapping all statements following the local variable declaration to the + * end of your scope into a try block that, as a finally action, closes the resource. + * + * Example: + * <pre> + * public void copyFile(String in, String out) throws IOException { + * @Cleanup FileInputStream inStream = new FileInputStream(in); + * @Cleamup FileOutputStream outStream = new FileOutputStream(out); + * byte[] b = new byte[65536]; + * while (true) { + * int r = inStream.read(b); + * if (r == -1) break; + * outStream.write(b, 0, r); + * } + * } + * </pre> + * + * Will generate: + * <pre> + * public void copyFile(String in, String out) throws IOException { + * @Cleanup FileInputStream inStream = new FileInputStream(in); + * try { + * @Cleamup FileOutputStream outStream = new FileOutputStream(out); + * try { + * byte[] b = new byte[65536]; + * while (true) { + * int r = inStream.read(b); + * if (r == -1) break; + * outStream.write(b, 0, r); + * } + * } finally { + * out.close(); + * } + * } finally { + * in.close(); + * } + * } + * </pre> + * + * Note that the final close method call, if it throws an exception, will overwrite any exception thrown + * in the main body of the generated try block. You should NOT rely on this behaviour - future versions of + * lombok intend to silently swallow any exception thrown by the cleanup method <i>_IF</i> the main body + * throws an exception as well, as the earlier exception is usually far more useful. + * + * However, in java 1.6, generating the code to do this is prohibitively complicated. + */ @Target(ElementType.LOCAL_VARIABLE) @Retention(RetentionPolicy.SOURCE) public @interface Cleanup { + /** The name of the method that cleans up the resource. By default, 'close'. The method must not have any parameters. */ String cleanupMethod() default "close"; } diff --git a/src/lombok/Data.java b/src/lombok/Data.java index f9b02b52..a9a70ee7 100644 --- a/src/lombok/Data.java +++ b/src/lombok/Data.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import java.lang.annotation.ElementType; @@ -5,6 +26,18 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Generates getters for all fields, a useful toString method, and hashCode and equals implementations that check + * all non-transient fields. Will also generate setters for all non-final fields, as well as a constructor. + * + * If any method to be generated already exists (in name - the return type or parameters are not relevant), then + * that method will not be generated by the Data annotation. + * + * <code>toString</code>, <code>equals</code>, and <code>hashCode</code> use the deepX variants in the + * <code>java.util.Arrays</code> utility class. Therefore, if your class has arrays that contain themselves, + * these methods will just loop endlessly until the inevitable <code>StackOverflowError</code>. This behaviour + * is no different from <code>java.util.ArrayList</code>, though. + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface Data { diff --git a/src/lombok/Getter.java b/src/lombok/Getter.java index d59ea672..581a252d 100644 --- a/src/lombok/Getter.java +++ b/src/lombok/Getter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import java.lang.annotation.ElementType; @@ -5,8 +26,33 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Put on any field to make lombok build a standard getter. + * + * Example: + * <pre> + * private @Getter int foo; + * </pre> + * + * will generate: + * + * <pre> + * public int getFoo() { + * return this.foo; + * } + * </pre> + * + * Note that fields of type <code>boolean</code> (but not <code>java.lang.Boolean</code>) will result in an + * <code>isFoo</code> name instead of <code>getFoo</code>. + * + * If any method named <code>getFoo</code>/<code>isFoo</code> exists, regardless of return type or parameters, no method is generated, + * and instead a compiler warning is emitted. + */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Getter { + /** + * If you want your setter to be non-public, you can specify an alternate access level here. + */ lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; } diff --git a/src/lombok/Lombok.java b/src/lombok/Lombok.java index 10a58e5a..400bf3ea 100644 --- a/src/lombok/Lombok.java +++ b/src/lombok/Lombok.java @@ -1,5 +1,29 @@ +/* + * Copyright © 2009 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; +/** + * Useful utility methods to manipulate lombok-generated code. + */ public class Lombok { /** * Throws any throwable 'sneakily' - you don't need to catch it, nor declare that you throw it onwards. @@ -15,6 +39,11 @@ public class Lombok { * about the concept of a 'checked exception'. All this method does is hide the act of throwing a checked exception * from the java compiler. * + * Note that this method has a return type of <code>RuntimeException</code> it is advised you always call this + * method as argument to the <code>throw</code> statement to avoid compiler errors regarding no return + * statement and similar problems. This method won't of course return an actual <code>RuntimeException</code> - + * it never returns, it always throws the provided exception. + * * @param t The throwable to throw without requiring you to catch its type. * @return A dummy RuntimeException; this method never returns normally, it <em>always</em> throws an exception! */ diff --git a/src/lombok/Setter.java b/src/lombok/Setter.java index b00d4158..9774c5c6 100644 --- a/src/lombok/Setter.java +++ b/src/lombok/Setter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import java.lang.annotation.ElementType; @@ -5,8 +26,30 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Put on any field to make lombok build a standard setter. + * + * Example: + * <pre> + * private @Setter int foo; + * </pre> + * + * will generate: + * + * <pre> + * public void setFoo(int foo) { + * this.foo = foo; + * } + * </pre> + * + * If any method named <code>setFoo</code> exists, regardless of return type or parameters, no method is generated, + * and instead a compiler warning is emitted. + */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Setter { + /** + * If you want your setter to be non-public, you can specify an alternate access level here. + */ lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; } diff --git a/src/lombok/SneakyThrows.java b/src/lombok/SneakyThrows.java index e9b31b3d..409429ea 100644 --- a/src/lombok/SneakyThrows.java +++ b/src/lombok/SneakyThrows.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import java.lang.annotation.ElementType; @@ -6,10 +27,42 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * DOCS: Requires lombok.jar at runtime. + * Sneaky throw will avoid javac's insistence that you either catch or throw onward any checked exceptions that + * statements in your method body declare they generate. + * + * Sneaky throw does not silently swallow, wrap into RuntimeException, or otherwise modify any exceptions of the listed + * checked exception types. The JVM does not check for the consistency of the checked exception system; javac does, + * and this annotation lets you opt out of its mechanism. + * + * You should use this annotation ONLY in the following two cases:<ol> + * <li>You are certain the listed exception can't actually ever happen, or only in vanishingly rare situations. + * You don't try to catch OutOfMemoryError on every statement either. Examples:<br> + * <code>IOException</code> in <code>ByteArrayOutputStream</code><br> + * <code>UnsupportedEncodingException</code> in new String(byteArray, "UTF-8").</li> + * <li>You know for certain the caller can handle the exception (for example, because the caller is + * an app manager that will handle all throwables that fall out of your method the same way), but due + * to interface restrictions you can't just add these exceptions to your 'throws' clause. + * + * Note that, as SneakyThrow is an implementation detail and <i>NOT</i> part of your method signature, it is + * a compile time error if none of the statements in your method body can throw a listed exception. + * + * <b><i>WARNING: </b></i>You must have lombok.jar available at the runtime of your app if you use SneakyThrows, + * because your code is rewritten to use {@link Lombok.sneakyThrow(Throwable)}. + * + * + * Example: + * <pre> + * @SneakyThrows(UnsupportedEncodingException.class) + * public void utf8ToString(byte[] bytes) { + * return new String(bytes, "UTF-8"); + * } + * </pre> + * + * @see Lombok.sneakyThrow(Throwable) */ @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @Retention(RetentionPolicy.SOURCE) public @interface SneakyThrows { + /** The exception type(s) you want to sneakily throw onward. */ Class<? extends Throwable>[] value(); } diff --git a/src/lombok/Synchronized.java b/src/lombok/Synchronized.java index 0c813eb7..655f95e4 100644 --- a/src/lombok/Synchronized.java +++ b/src/lombok/Synchronized.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import java.lang.annotation.ElementType; @@ -5,8 +26,21 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Almost exactly like putting the 'synchronized' keyword on a method, except will synchronize on a private internal + * Object, so that other code not under your control doesn't meddle with your thread management by locking on + * your own instance. + * + * For non-static methods, a field named <code>$lock</code> is used, and for static methods, + * <code>$LOCK</code> is used. These will be generated if needed and if they aren't already present. The contents + * of the fields will be serializable. + */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Synchronized { + /** + * Optional: specify the name of a different field to lock on. It is a compile time error if this field + * doesn't already exist (the fields are automatically generated only if you don't specify a specific name. + */ String value() default ""; } diff --git a/src/lombok/core/AST.java b/src/lombok/core/AST.java index 24e128b2..ef752d1a 100644 --- a/src/lombok/core/AST.java +++ b/src/lombok/core/AST.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.core; import static lombok.Lombok.sneakyThrow; @@ -14,7 +35,15 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +/** + * Lombok wraps the AST produced by a target platform into its own AST system, mostly because both eclipse and javac + * do not allow upward traversal (from a method to its owning type, for example). + * + * @param N The common type of all AST nodes in the internal representation of the target platform. + * For example, JCTree for javac, and ASTNode for eclipse. + */ public abstract class AST<N> { + /** The kind of node represented by a given AST.Node object. */ public enum Kind { COMPILATION_UNIT, TYPE, FIELD, INITIALIZER, METHOD, ANNOTATION, ARGUMENT, LOCAL, STATEMENT; } @@ -28,29 +57,52 @@ public abstract class AST<N> { this.fileName = fileName == null ? "(unknown).java" : fileName; } + /** Set the node object that wraps the internal Compilation Unit node. */ protected void setTop(Node top) { this.top = top; } + /** + * Return the content of the package declaration on this AST's top (Compilation Unit) node. + * + * Example: "java.util". + */ public abstract String getPackageDeclaration(); + /** + * Return the contents of each non-static import statement on this AST's top (Compilation Unit) node. + * + * Example: "java.util.IOException". + */ public abstract Collection<String> getImportStatements(); - protected <T extends Node> T putInMap(T parent) { - nodeMap.put(parent.get(), parent); - identityDetector.put(parent.get(), null); - return parent; + /** + * Puts the given node in the map so that javac/eclipse's own internal AST object can be translated to + * an AST.Node object. Also registers the object as visited to avoid endless loops. + */ + protected <T extends Node> T putInMap(T node) { + nodeMap.put(node.get(), node); + identityDetector.put(node.get(), null); + return node; } + /** Returns the node map, that can map javac/eclipse internal AST objects to AST.Node objects. */ protected Map<N, Node> getNodeMap() { return nodeMap; } + /** Clears the registry that avoids endless loops, and empties the node map. The existing node map + * object is left untouched, and instead a new map is created. */ protected void clearState() { identityDetector = new IdentityHashMap<N, Void>(); nodeMap = new IdentityHashMap<N, Node>(); } + /** + * Marks the stated node as handled (to avoid endless loops if 2 nodes refer to each other, or a node + * refers to itself). Will then return true if it was already set as handled before this call - in which + * case you should do nothing lest the AST build process loops endlessly. + */ protected boolean setAndGetAsHandled(N node) { if ( identityDetector.containsKey(node) ) return true; identityDetector.put(node, null); @@ -61,10 +113,12 @@ public abstract class AST<N> { return fileName; } + /** The AST.Node object representing the Compilation Unit. */ public Node top() { return top; } + /** Maps a javac/eclipse internal AST Node to the appropriate AST.Node object. */ public Node get(N node) { return nodeMap.get(node); } @@ -86,14 +140,33 @@ public abstract class AST<N> { return targetNode; } + /** An instance of this class wraps an eclipse/javac internal node object. */ public abstract class Node { protected final Kind kind; protected final N node; protected final List<? extends Node> children; protected Node parent; + + /** This flag has no specified meaning; you can set and retrieve it. + * + * In practice, for annotation nodes it means: Some AnnotationHandler finished whatever changes were required, + * and for all other nodes it means: This node was made by a lombok operation. + */ protected boolean handled; + + /** structurally significant are those nodes that can be annotated in java 1.6 or are method-like toplevels, + * so fields, local declarations, method arguments, methods, types, the Compilation Unit itself, and initializers. */ protected boolean isStructurallySignificant; + /** + * Creates a new Node object that represents the provided node. + * + * Make sure you manually set the parent correctly. + * + * @param node The AST object in the target parser's own internal AST tree that this node object will represent. + * @param children A list of child nodes. Passing in null results in the children list being empty, not null. + * @param kind The kind of node represented by this object. + */ protected Node(N node, List<? extends Node> children, Kind kind) { this.kind = kind; this.node = node; @@ -102,29 +175,57 @@ public abstract class AST<N> { this.isStructurallySignificant = calculateIsStructurallySignificant(); } + /** {@inheritDoc} */ @Override public String toString() { return String.format("NODE %s (%s) %s%s", kind, node == null ? "(NULL)" : node.getClass(), handled ? "[HANDLED]" : "", node == null ? "" : node); } + /** + * Convenient shortcut to the owning JavacAST object's getPackageDeclaration method. + * + * @see AST#getPackageDeclaration() + */ public String getPackageDeclaration() { return AST.this.getPackageDeclaration(); } + /** + * Convenient shortcut to the owning JavacAST object's getImportStatements method. + * + * @see AST#getImportStatements() + */ public Collection<String> getImportStatements() { return AST.this.getImportStatements(); } + /** + * See {@link #isStructurallySignificant}. + */ protected abstract boolean calculateIsStructurallySignificant(); + /** + * Convenient shortcut to the owning JavacAST object's getNodeFor method. + * + * @see AST#getNodeFor() + */ public Node getNodeFor(N obj) { return AST.this.get(obj); } + /** + * @return The javac/eclipse internal AST object wrapped by this AST.Node object. + */ public N get() { return node; } + /** + * Replaces the AST node represented by this node object with the provided node. This node must + * have a parent, obviously, for this to work. + * + * Also affects the underlying (eclipse/javac) AST. + */ @SuppressWarnings("unchecked") public Node replaceWith(N newN, Kind kind) { Node newNode = buildTree(newN, kind); @@ -137,6 +238,11 @@ public abstract class AST<N> { return newNode; } + /** + * Replaces the stated node with a new one. The old node must be a direct child of this node. + * + * Also affects the underlying (eclipse/javac) AST. + */ public void replaceChildNode(N oldN, N newN) { replaceStatementInNode(get(), oldN, newN); } @@ -169,27 +275,58 @@ public abstract class AST<N> { return parent; } + /** + * Returns all children nodes. + * + * A copy is created, so changing the list has no effect. Also, while iterating through this list, + * you may add, remove, or replace children without causing ConcurrentModificationExceptions. + */ public Collection<? extends Node> down() { return new ArrayList<Node>(children); } + /** + * returns the value of the 'handled' flag. + * + * @see #handled + */ public boolean isHandled() { return handled; } + /** + * Sets the handled flag, then returns 'this'. + * + * @see #handled + */ public Node setHandled() { this.handled = true; return this; } + /** + * Convenient shortcut to the owning JavacAST object's top method. + * + * @see AST#top() + */ public Node top() { return top; } + /** + * Convenient shortcut to the owning JavacAST object's getFileName method. + * + * @see AST#getFileName() + */ public String getFileName() { return fileName; } + /** + * Adds the stated node as a direct child of this node. + * + * Does not change the underlying (javac/eclipse) AST, only the wrapped view. + */ @SuppressWarnings("unchecked") public Node add(N newChild, Kind kind) { Node n = buildTree(newChild, kind); if ( n == null ) return null; @@ -221,18 +358,30 @@ public abstract class AST<N> { nodeMap.remove(get()); } + /** + * Removes the stated node, which must be a direct child of this node, from the AST. + * + * Does not change the underlying (javac/eclipse) AST, only the wrapped view. + */ public void removeChild(Node child) { children.remove(child); } + /** + * Sets the handled flag on this node, and all child nodes, then returns this. + * + * @see #handled + */ public Node recursiveSetHandled() { this.handled = true; for ( Node child : children ) child.recursiveSetHandled(); return this; } + /** Generate a compiler error on this node. */ public abstract void addError(String message); + /** Generate a compiler warning on this node. */ public abstract void addWarning(String message); /** @@ -245,10 +394,16 @@ public abstract class AST<N> { } } + /** Build an AST.Node object for the stated internal (javac/eclipse) AST Node object. */ protected abstract Node buildTree(N item, Kind kind); + /** + * Represents a field that contains AST children. + */ protected static class FieldAccess { + /** The actual field. */ public final Field field; + /** Dimensions of the field. Works for arrays, or for java.util.collections. */ public final int dim; FieldAccess(Field field, int dim) { @@ -258,6 +413,11 @@ public abstract class AST<N> { } private static Map<Class<?>, Collection<FieldAccess>> fieldsOfASTClasses = new HashMap<Class<?>, Collection<FieldAccess>>(); + + /** Returns FieldAccess objects for the stated class. Each field that contains objects of the kind returned by + * {@link #getStatementTypes()}, either directly or inside of an array or java.util.collection (or array-of-arrays, + * or collection-of-collections, etcetera), is returned. + */ protected Collection<FieldAccess> fieldsOf(Class<?> c) { Collection<FieldAccess> fields = fieldsOfASTClasses.get(c); if ( fields != null ) return fields; @@ -305,14 +465,23 @@ public abstract class AST<N> { } else return Object.class; } + /** + * The supertypes which are considered AST Node children. Usually, the Statement, and the Expression, + * though some platforms (such as eclipse) group these under one common supertype. */ protected abstract Collection<Class<? extends N>> getStatementTypes(); + /** + * buildTree implementation that uses reflection to find all child nodes by way of inspecting + * the fields. */ protected <T extends Node> Collection<T> buildWithField(Class<T> nodeType, N statement, FieldAccess fa) { List<T> list = new ArrayList<T>(); buildWithField0(nodeType, statement, fa, list); return list; } + /** + * Uses reflection to find the given direct child on the given statement, and replace it with a new child. + */ protected boolean replaceStatementInNode(N statement, N oldN, N newN) { for ( FieldAccess fa : fieldsOf(statement.getClass()) ) { if ( replaceStatementInField(fa, statement, oldN, newN) ) return true; diff --git a/src/lombok/core/AnnotationValues.java b/src/lombok/core/AnnotationValues.java index 432d507f..ee434f1f 100644 --- a/src/lombok/core/AnnotationValues.java +++ b/src/lombok/core/AnnotationValues.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.core; import java.lang.annotation.Annotation; @@ -10,13 +31,23 @@ import java.util.Collections; import java.util.List; import java.util.Map; +/** + * Represents a single annotation in a source file and can be used to query the parameters present on it. + */ public class AnnotationValues<A extends Annotation> { private final Class<A> type; private final Map<String, AnnotationValue> values; private final AST<?>.Node ast; - + + /** + * Represents a single method on the annotation class. For example, the value() method on the Getter annotation. + */ public static class AnnotationValue { + /** A list of the raw expressions. List is size 1 unless an array is provided. */ public final List<String> raws; + + /** 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; private final AST<?>.Node node; @@ -33,7 +64,9 @@ public class AnnotationValues<A extends Annotation> { this.valueGuesses = Collections.singletonList(valueGuess); } - /** When the value is an array type. */ + /** + * Like the other constructor, but used for when the annotation method is initialized with an array value. + */ public AnnotationValue(AST<?>.Node node, List<String> raws, List<Object> valueGuesses) { this.node = node; this.raws = raws; @@ -52,21 +85,39 @@ public class AnnotationValues<A extends Annotation> { node.addError(message); } + /** {@inheritDoc} */ @Override public String toString() { return "raws: " + raws + " valueGuesses: " + valueGuesses; } } + /** + * Creates a new AnnotationValues. + * + * @param type The annotation type. For example, "Getter.class" + * @param values a Map of method names to AnnotationValue instances, for example 'value -> annotationValue instance'. + * @param ast The Annotation node. + */ public AnnotationValues(Class<A> type, Map<String, AnnotationValue> values, AST<?>.Node ast) { this.type = type; this.values = values; this.ast = ast; } + /** + * Thrown on the fly if an actual annotation instance procured via the {@link #getInstance()} method is queried + * for a method for which this AnnotationValues instance either doesn't have a guess or can't manage to fit + * the guess into the required data type. + */ public static class AnnotationValueDecodeFail extends RuntimeException { private static final long serialVersionUID = 1L; + /** The index into an array initializer (e.g. if the second value in an array initializer is + * an integer constant expression like '5+SomeOtherClass.CONSTANT', this exception will be thrown, + * and you'll get a '1' for idx. */ public final int idx; + + /** The AnnotationValue object that goes with the annotation method for which the failure occurred. */ public final AnnotationValue owner; public AnnotationValueDecodeFail(AnnotationValue owner, String msg, int idx) { @@ -83,8 +134,15 @@ public class AnnotationValues<A extends Annotation> { private A cachedInstance = null; + /** + * Creates an actual annotation instance. You can use this to query any annotation methods, except for + * those annotation methods with class literals, as those can most likely not be turned into Class objects. + * + * If some of the methods cannot be implemented, this method still works; it's only when you call a method + * that has a problematic value that an AnnotationValueDecodeFail exception occurs. + */ @SuppressWarnings("unchecked") - public A getInstance() throws AnnotationValueDecodeFail { + public A getInstance() { if ( cachedInstance != null ) return cachedInstance; InvocationHandler invocations = new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { @@ -217,16 +275,32 @@ public class AnnotationValues<A extends Annotation> { "Can't translate a " + guess.getClass() + " to the expected " + expected, pos); } + /** + * Returns the raw expressions used for the provided annotationMethodName. + * + * You should use this method for annotation methods that return Class objects. Remember that + * class literals end in ".class" which you probably want to strip off. + */ public List<String> getRawExpressions(String annotationMethodName) { AnnotationValue v = values.get(annotationMethodName); return v == null ? Collections.<String>emptyList() : v.raws; } + /** + * Convenience method to return the first result in a {@link getRawExpressions(String)} call. + * + * You should use this method if the annotation method is not an array type. + */ public String getRawExpression(String annotationMethodName) { List<String> l = getRawExpressions(annotationMethodName); return l.isEmpty() ? null : l.get(0); } + /** + * Attempts to translate class literals to their fully qualified names, such as 'Throwable.class' to 'java.lang.Throwable'. + * + * This process is at best a guess, but it will take into account import statements. + */ public List<String> getProbableFQTypes(String annotationMethodName) { List<String> result = new ArrayList<String>(); AnnotationValue v = values.get(annotationMethodName); @@ -236,6 +310,16 @@ public class AnnotationValues<A extends Annotation> { return result; } + /** + * Convenience method to return the first result in a {@link getProbableFQType(String)} call. + * + * You should use this method if the annotation method is not an array type. + */ + public String getProbableFQType(String annotationMethodName) { + List<String> l = getProbableFQTypes(annotationMethodName); + return l.isEmpty() ? null : l.get(0); + } + private String toFQ(String typeName) { Class<?> c; boolean fqn = typeName.indexOf('.') > -1; @@ -279,9 +363,4 @@ public class AnnotationValues<A extends Annotation> { return null; } } - - public String getProbableFQType(String annotationMethodName) { - List<String> l = getProbableFQTypes(annotationMethodName); - return l.isEmpty() ? null : l.get(0); - } } diff --git a/src/lombok/core/PrintAST.java b/src/lombok/core/PrintAST.java index 6d1eaafd..943bf298 100644 --- a/src/lombok/core/PrintAST.java +++ b/src/lombok/core/PrintAST.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.core; import java.lang.annotation.ElementType; @@ -5,14 +26,25 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Will print the tree structure of annotated node and all its children. + * + * This annotation is useful only for those working on Lombok, for example to test if a Lombok handlers is doing its + * job correctly, or to see what the imagined endresult of a transformation is supposed to look like. + */ @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface PrintAST { + /** + * Normally, the AST is printed to standard out, but you can pick a filename instead. Useful for many IDEs + * which don't have a console unless you start them from the command line. + */ String outfile() default ""; /** - * Normally, the printer will print each node focusing on the node (E.g. classname, and such). By setting printContent to true, - * methods, initializers, and other statement-containing elements actually print their java code instead of element class names. + * Normally, the printer will print each node focusing on the node (E.g. classname, and such). + * By setting printContent to true, methods, initializers, and other statement-containing elements + * actually print their java code instead of a tree view of internal AST nodes. */ boolean printContent() default false; } diff --git a/src/lombok/core/SpiLoadUtil.java b/src/lombok/core/SpiLoadUtil.java index b26dd747..b3b70f27 100644 --- a/src/lombok/core/SpiLoadUtil.java +++ b/src/lombok/core/SpiLoadUtil.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.core; import java.io.BufferedReader; @@ -16,13 +37,44 @@ import java.util.Set; import lombok.Lombok; +/** + * The java core libraries have a SPI discovery system, but it works only in Java 1.6 and up. For at least eclipse, + * lombok actually works in java 1.5, so we've rolled our own SPI discovery system. + * + * It is not API compatible with <code>ServiceLoader</code>. + * + * @see java.util.ServiceLoader + */ public class SpiLoadUtil { - private SpiLoadUtil() {} + private SpiLoadUtil() { + //Prevent instantiation + } + /** + * Returns an iterator of instances that, at least according to the spi discovery file, are implementations + * of the stated class. + * + * Like ServiceLoader, each listed class is turned into an instance by calling the public no-args constructor. + * + * Convenience method that calls the more elaborate {@link #findServices(Class, ClassLoader)} method with + * this {@link java.lang.Thread}'s context class loader as <code>ClassLoader</code>. + * + * @param target class to find implementations for. + */ public static <C> Iterator<C> findServices(Class<C> target) throws IOException { return findServices(target, Thread.currentThread().getContextClassLoader()); } + /** + * Returns an iterator of class objects that, at least according to the spi discovery file, are implementations + * of the stated class. + * + * Like ServiceLoader, each listed class is turned into an instance by calling the public no-args constructor. + * + * @param target class to find implementations for. + * @param loader The classloader object to use to both the spi discovery files, as well as the loader to use + * to make the returned instances. + */ public static <C> Iterator<C> findServices(final Class<C> target, final ClassLoader loader) throws IOException { Enumeration<URL> resources = loader.getResources("META-INF/services/" + target.getName()); final Set<String> entries = new LinkedHashSet<String>(); @@ -70,6 +122,12 @@ public class SpiLoadUtil { } } + /** + * This method will find the <code>T</code> in <code>public class Foo extends BaseType<T>. + * + * It returns an annotation type because it is used exclusively to figure out which annotations are + * being handled by {@link lombok.eclipse.EclipseAnnotationHandler} and {@link lombok.javac.JavacAnnotationHandler}. + */ @SuppressWarnings("unchecked") public static Class<? extends Annotation> findAnnotationClass(Class<?> c, Class<?> base) { if ( c == Object.class || c == null ) return null; diff --git a/src/lombok/core/TransformationsUtil.java b/src/lombok/core/TransformationsUtil.java index 8aea09a4..6b454b51 100644 --- a/src/lombok/core/TransformationsUtil.java +++ b/src/lombok/core/TransformationsUtil.java @@ -1,8 +1,50 @@ +/* + * Copyright © 2009 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.core; +/** + * Container for static utility methods useful for some of the standard lombok transformations, regardless of + * target platform (e.g. useful for both javac and eclipse lombok implementations). + */ public class TransformationsUtil { - private TransformationsUtil() {} + private TransformationsUtil() { + //Prevent instantiation + } + /** + * Generates a getter name from a given field name. + * + * Strategy: + * + * First, pick a prefix. 'get' normally, but 'is' if <code>isBoolean</code> is true. + * + * Then, check if the first character of the field is lowercase. If so, check if the second character + * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character. + * + * return the prefix plus the possibly title/uppercased first character, and the rest of the field name. + * + * @param fieldName the name of the field. + * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide <code>false</code>. + */ public static String toGetterName(CharSequence fieldName, boolean isBoolean) { final String prefix = isBoolean ? "is" : "get"; @@ -11,16 +53,33 @@ public class TransformationsUtil { return buildName(prefix, fieldName.toString()); } + /** + * Generates a getter name from a given field name. + * + * Strategy: + * + * Check if the first character of the field is lowercase. If so, check if the second character + * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character. + * + * return "set" plus the possibly title/uppercased first character, and the rest of the field name. + * + * @param fieldName the name of the field. + */ + public static String toSetterName(CharSequence fieldName) { + return buildName("set", fieldName.toString()); + } + private static String buildName(String prefix, String suffix) { if ( suffix.length() == 0 ) return prefix; char first = suffix.charAt(0); - if ( Character.isLowerCase(first) ) - suffix = String.format("%s%s", Character.toTitleCase(first), suffix.subSequence(1, suffix.length())); + if ( Character.isLowerCase(first) ) { + boolean useUpperCase = suffix.length() > 2 && + (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1))); + suffix = String.format("%s%s", + useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first), + suffix.subSequence(1, suffix.length())); + } return String.format("%s%s", prefix, suffix); } - - public static String toSetterName(CharSequence fieldName) { - return buildName("set", fieldName.toString()); - } } diff --git a/src/lombok/core/TypeLibrary.java b/src/lombok/core/TypeLibrary.java index c6789d7e..41b70a68 100644 --- a/src/lombok/core/TypeLibrary.java +++ b/src/lombok/core/TypeLibrary.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.core; import java.util.Collection; @@ -7,9 +28,23 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +/** + * Library of types, which can be used to look up potential matching types. + * + * For example, if you put 'foo.Spork' and 'bar.Spork' into the library, and then ask for + * all compatible types given the type 'Spork', you'll get both of them, but you'll only + * get the one if you ask for compatible types given 'foo.Spork'. + * + * Useful to 'guess' if a given annotation AST node matches an annotation handler's target annotation. + */ public class TypeLibrary { private final Map<String, Set<String>> simpleToQualifiedMap = new HashMap<String, Set<String>>(); + /** + * Add a type to the library. + * + * @param fullyQualifiedTypeName the FQN type name, such as 'java.lang.String'. + */ public void addType(String fullyQualifiedTypeName) { int idx = fullyQualifiedTypeName.lastIndexOf('.'); if ( idx == -1 ) throw new IllegalArgumentException( @@ -32,6 +67,11 @@ public class TypeLibrary { return this; } + /** + * Returns all items in the type library that may be a match to the provided type. + * + * @param typeReference something like 'String' or even 'java.lang.String'. + */ public Collection<String> findCompatible(String typeReference) { Set<String> result = simpleToQualifiedMap.get(typeReference); return result == null ? Collections.<String>emptySet() : result; diff --git a/src/lombok/core/TypeResolver.java b/src/lombok/core/TypeResolver.java index 1e356f89..3adc82ce 100644 --- a/src/lombok/core/TypeResolver.java +++ b/src/lombok/core/TypeResolver.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.core; import java.util.Collection; @@ -7,10 +28,17 @@ import java.util.Set; import lombok.core.AST.Kind; +/** + * Capable of resolving a simple type name such as 'String' into 'java.lang.String'. + */ public class TypeResolver { private final TypeLibrary library; private Collection<String> imports; + /** + * Creates a new TypeResolver that can be used to resolve types in a given library, encountered in + * a source file with the provided package and import statements. + */ public TypeResolver(TypeLibrary library, String packageString, Collection<String> importStrings) { this.library = library; this.imports = makeImportList(packageString, importStrings); @@ -23,6 +51,11 @@ public class TypeResolver { return imports; } + /** + * Finds type matches for the stated type reference. The provided context is scanned for local type names + * that shadow type names listed in import statements. If such a shadowing occurs, no matches are returned + * for any shadowed types, as you would expect. + */ public Collection<String> findTypeMatches(AST<?>.Node context, String typeRef) { Collection<String> potentialMatches = library.findCompatible(typeRef); if ( potentialMatches.isEmpty() ) return Collections.emptyList(); diff --git a/src/lombok/core/Version.java b/src/lombok/core/Version.java index cb349aaf..119dcc2e 100644 --- a/src/lombok/core/Version.java +++ b/src/lombok/core/Version.java @@ -1,5 +1,29 @@ +/* + * Copyright © 2009 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.core; +/** + * This class just holds lombok's current version. + */ public class Version { private static final String VERSION = "0.4"; @@ -7,10 +31,16 @@ public class Version { //Prevent instantiation } + /** + * Prints the version followed by a newline, and exits. + */ public static void main(String[] args) { System.out.println(VERSION); } + /** + * Get the current Lombok version. + */ public static String getVersion() { return VERSION; } diff --git a/src/lombok/eclipse/Eclipse.java b/src/lombok/eclipse/Eclipse.java index 549de3c0..84a65da1 100644 --- a/src/lombok/eclipse/Eclipse.java +++ b/src/lombok/eclipse/Eclipse.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse; import java.lang.reflect.Method; @@ -42,25 +63,43 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.osgi.framework.Bundle; public class Eclipse { + /** + * Eclipse's Parser class is instrumented to not attempt to fill in the body of any method or initializer + * or field initialization if this flag is set. Set it on the flag field of + * any method, field, or initializer you create! + */ public static final int ECLIPSE_DO_NOT_TOUCH_FLAG = ASTNode.Bit24; + private Eclipse() { //Prevent instantiation } private static final String DEFAULT_BUNDLE = "org.eclipse.jdt.core"; + /** + * Generates an error in the eclipse error log. Note that most people never look at it! + */ public static void error(CompilationUnitDeclaration cud, String message) { error(cud, message, DEFAULT_BUNDLE, null); } + /** + * Generates an error in the eclipse error log. Note that most people never look at it! + */ public static void error(CompilationUnitDeclaration cud, String message, Throwable error) { error(cud, message, DEFAULT_BUNDLE, error); } + /** + * Generates an error in the eclipse error log. Note that most people never look at it! + */ public static void error(CompilationUnitDeclaration cud, String message, String bundleName) { error(cud, message, bundleName, null); } + /** + * Generates an error in the eclipse error log. Note that most people never look at it! + */ public static void error(CompilationUnitDeclaration cud, String message, String bundleName, Throwable error) { Bundle bundle = Platform.getBundle(bundleName); if ( bundle == null ) { @@ -74,6 +113,10 @@ public class Eclipse { if ( cud != null ) EclipseAST.addProblemToCompilationResult(cud, false, message + " - See error log.", 0, 0); } + /** + * For 'speed' reasons, eclipse works a lot with char arrays. I have my doubts this was a fruitful exercise, + * but we need to deal with it. This turns [[java][lang][String]] into "java.lang.String". + */ static String toQualifiedName(char[][] typeName) { StringBuilder sb = new StringBuilder(); boolean first = true; @@ -84,6 +127,11 @@ public class Eclipse { return sb.toString(); } + /** + * 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 + * is complicated and there's no clone method on TypeParameter itself. This method can clone them. + */ public static TypeParameter[] copyTypeParams(TypeParameter[] params) { if ( params == null ) return null; TypeParameter[] out = new TypeParameter[params.length]; @@ -106,6 +154,10 @@ public class Eclipse { return out; } + /** + * Convenience method that creates a new array and copies each TypeReference in the source array via + * {@link #copyType(TypeReference)}. + */ public static TypeReference[] copyTypes(TypeReference[] refs) { if ( refs == null ) return null; TypeReference[] outs = new TypeReference[refs.length]; @@ -116,6 +168,11 @@ public class Eclipse { return outs; } + /** + * You can't share TypeReference objects or subtle errors start happening. + * Unfortunately the TypeReference type hierarchy is complicated and there's no clone + * method on TypeReference itself. This method can clone them. + */ public static TypeReference copyType(TypeReference ref) { if ( ref instanceof ParameterizedQualifiedTypeReference ) { ParameterizedQualifiedTypeReference iRef = (ParameterizedQualifiedTypeReference) ref; @@ -179,6 +236,11 @@ public class Eclipse { return ref; } + /** + * Checks if the provided annotation type is likely to be the intended type for the given annotation node. + * + * This is a guess, but a decent one. + */ public static boolean annotationTypeMatches(Class<? extends java.lang.annotation.Annotation> type, Node node) { if ( node.getKind() != Kind.ANNOTATION ) return false; TypeReference typeRef = ((Annotation)node.get()).type; @@ -197,6 +259,9 @@ public class Eclipse { return false; } + /** + * Provides AnnotationValues with the data it needs to do its thing. + */ public static <A extends java.lang.annotation.Annotation> AnnotationValues<A> createAnnotation(Class<A> type, final Node annotationNode) { final Annotation annotation = (Annotation) annotationNode.get(); diff --git a/src/lombok/eclipse/EclipseAST.java b/src/lombok/eclipse/EclipseAST.java index 5018f484..cb530f0e 100644 --- a/src/lombok/eclipse/EclipseAST.java +++ b/src/lombok/eclipse/EclipseAST.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse; import java.util.ArrayList; @@ -25,13 +46,31 @@ import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; import org.eclipse.jdt.internal.compiler.util.Util; +/** + * Wraps around eclipse's internal AST view to add useful features as well as the ability to visit parents from children, + * something eclipse's own AST system does not offer. + */ public class EclipseAST extends AST<ASTNode> { + /** + * Creates a new EclipseAST of the provided Compilation Unit. + * + * @param ast The compilation unit, which serves as the top level node in the tree to be built. + */ + public EclipseAST(CompilationUnitDeclaration ast) { + super(toFileName(ast)); + this.compilationUnitDeclaration = ast; + setTop(buildCompilationUnit(ast)); + this.completeParse = isComplete(ast); + } + + /** {@inheritDoc} */ @Override public String getPackageDeclaration() { CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().get(); ImportReference pkg = cud.currentPackage; return pkg == null ? null : Eclipse.toQualifiedName(pkg.getImportName()); } + /** {@inheritDoc} */ @Override public Collection<String> getImportStatements() { List<String> imports = new ArrayList<String>(); CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().get(); @@ -44,25 +83,38 @@ public class EclipseAST extends AST<ASTNode> { return imports; } + /** + * Runs through the entire AST, starting at the compilation unit, calling the provided visitor's visit methods + * for each node, depth first. + */ public void traverse(EclipseASTVisitor visitor) { top().traverse(visitor); } - void traverseChildren(EclipseASTVisitor visitor, Node node) { + private void traverseChildren(EclipseASTVisitor visitor, Node node) { for ( Node child : node.down() ) { child.traverse(visitor); } } + /** + * Eclipse starts off with a 'diet' parse which leaves method bodies blank, amongst other shortcuts. + * + * For such diet parses, this method returns false, otherwise it returns true. Any lombok processor + * that needs the contents of methods should just do nothing (and return false so it gets another shot later!) + * when this is false. + */ public boolean isCompleteParse() { return completeParse; } + /** {@inheritDoc} */ @Override public Node top() { return (Node) super.top(); } - public Node get(ASTNode node) { + /** {@inheritDoc} */ + @Override public Node get(ASTNode node) { return (Node) super.get(node); } @@ -72,7 +124,7 @@ public class EclipseAST extends AST<ASTNode> { final int sourceStart; final int sourceEnd; - public ParseProblem(boolean isWarning, String message, int sourceStart, int sourceEnd) { + ParseProblem(boolean isWarning, String message, int sourceStart, int sourceEnd) { this.isWarning = isWarning; this.message = message; this.sourceStart = sourceStart; @@ -100,6 +152,10 @@ public class EclipseAST extends AST<ASTNode> { propagateProblems(); } + /** + * Adds a problem to the provided CompilationResult object so that it will show up + * in the Problems/Warnings view. + */ static void addProblemToCompilationResult(CompilationUnitDeclaration ast, boolean isWarning, String message, int sourceStart, int sourceEnd) { if ( ast.compilationResult == null ) return; @@ -141,11 +197,20 @@ public class EclipseAST extends AST<ASTNode> { } } + /** + * Eclipse specific version of the AST.Node class. + */ public final class Node extends AST<ASTNode>.Node { + /** + * See the {@link AST.Node} constructor for information. + */ Node(ASTNode node, List<Node> children, Kind kind) { super(node, children, kind); } + /** + * Visits this node and all child nodes depth-first, calling the provided visitor's visit methods. + */ public void traverse(EclipseASTVisitor visitor) { switch ( getKind() ) { case COMPILATION_UNIT: @@ -219,6 +284,7 @@ public class EclipseAST extends AST<ASTNode> { } } + /** {@inheritDoc} */ @Override public String getName() { final char[] n; if ( node instanceof TypeDeclaration ) n = ((TypeDeclaration)node).name; @@ -230,18 +296,22 @@ public class EclipseAST extends AST<ASTNode> { return n == null ? null : new String(n); } + /** {@inheritDoc} */ @Override public void addError(String message) { this.addError(message, this.get().sourceStart, this.get().sourceEnd); } + /** Generate a compiler error that shows the wavy underline from-to the stated character positions. */ public void addError(String message, int sourceStart, int sourceEnd) { addProblem(new ParseProblem(false, message, sourceStart, sourceEnd)); } + /** {@inheritDoc} */ @Override public void addWarning(String message) { this.addWarning(message, this.get().sourceStart, this.get().sourceEnd); } + /** Generate a compiler warning that shows the wavy underline from-to the stated character positions. */ public void addWarning(String message, int sourceStart, int sourceEnd) { addProblem(new ParseProblem(true, message, sourceStart, sourceEnd)); } @@ -251,6 +321,7 @@ public class EclipseAST extends AST<ASTNode> { return (Node) super.up(); } + /** {@inheritDoc} */ @Override protected boolean calculateIsStructurallySignificant() { if ( node instanceof TypeDeclaration ) return true; if ( node instanceof AbstractMethodDeclaration ) return true; @@ -281,6 +352,11 @@ public class EclipseAST extends AST<ASTNode> { return (Node) super.top(); } + /** + * Convenient shortcut to the owning EclipseAST object's isCompleteParse method. + * + * @see JavacAST#isCompleteParse() + */ public boolean isCompleteParse() { return completeParse; } @@ -289,17 +365,15 @@ public class EclipseAST extends AST<ASTNode> { private final CompilationUnitDeclaration compilationUnitDeclaration; private boolean completeParse; - public EclipseAST(CompilationUnitDeclaration ast) { - super(toFileName(ast)); - this.compilationUnitDeclaration = ast; - setTop(buildCompilationUnit(ast)); - this.completeParse = isComplete(ast); - } - private static String toFileName(CompilationUnitDeclaration ast) { return ast.compilationResult.fileName == null ? null : new String(ast.compilationResult.fileName); } + /** + * Call to move an EclipseAST generated for a diet parse to rebuild itself for the full parse - + * with filled in method bodies and such. Also propagates problems and errors, which in diet parse + * mode can't be reliably added to the problems/warnings view. + */ public void reparse() { propagateProblems(); if ( completeParse ) return; @@ -315,6 +389,7 @@ public class EclipseAST extends AST<ASTNode> { return (unit.bits & ASTNode.HasAllMethodBodies) != 0; } + /** {@inheritDoc} */ @Override protected Node buildTree(ASTNode node, Kind kind) { switch ( kind ) { case COMPILATION_UNIT: @@ -459,6 +534,8 @@ public class EclipseAST extends AST<ASTNode> { return putInMap(new Node(statement, childNodes, Kind.STATEMENT)); } + /** For eclipse, only Statement counts, as Expression is a subclass of it, eventhough this isn't + * entirely correct according to the JLS spec (only some expressions can be used as statements, not all of them). */ @Override protected Collection<Class<? extends ASTNode>> getStatementTypes() { return Collections.<Class<? extends ASTNode>>singleton(Statement.class); } diff --git a/src/lombok/eclipse/EclipseASTAdapter.java b/src/lombok/eclipse/EclipseASTAdapter.java index da040037..bb185670 100644 --- a/src/lombok/eclipse/EclipseASTAdapter.java +++ b/src/lombok/eclipse/EclipseASTAdapter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse; import lombok.eclipse.EclipseAST.Node; @@ -12,26 +33,71 @@ import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +/** + * Standard adapter for the {@link EclipseASTVisitor} interface. Every method on that interface + * has been implemented with an empty body. Override whichever methods you need. + */ public abstract class EclipseASTAdapter implements EclipseASTVisitor { + /** {@inheritDoc} */ public void visitCompilationUnit(Node top, CompilationUnitDeclaration unit) {} + + /** {@inheritDoc} */ public void endVisitCompilationUnit(Node top, CompilationUnitDeclaration unit) {} + + /** {@inheritDoc} */ public void visitType(Node typeNode, TypeDeclaration type) {} + + /** {@inheritDoc} */ public void visitAnnotationOnType(TypeDeclaration type, Node annotationNode, Annotation annotation) {} + + /** {@inheritDoc} */ public void endVisitType(Node typeNode, TypeDeclaration type) {} + + /** {@inheritDoc} */ public void visitInitializer(Node initializerNode, Initializer initializer) {} + + /** {@inheritDoc} */ public void endVisitInitializer(Node initializerNode, Initializer initializer) {} + + /** {@inheritDoc} */ public void visitField(Node fieldNode, FieldDeclaration field) {} + + /** {@inheritDoc} */ public void visitAnnotationOnField(FieldDeclaration field, Node annotationNode, Annotation annotation) {} + + /** {@inheritDoc} */ public void endVisitField(Node fieldNode, FieldDeclaration field) {} + + /** {@inheritDoc} */ public void visitMethod(Node methodNode, AbstractMethodDeclaration method) {} + + /** {@inheritDoc} */ public void visitAnnotationOnMethod(AbstractMethodDeclaration method, Node annotationNode, Annotation annotation) {} + + /** {@inheritDoc} */ public void endVisitMethod(Node methodNode, AbstractMethodDeclaration method) {} + + /** {@inheritDoc} */ public void visitMethodArgument(Node argNode, Argument arg, AbstractMethodDeclaration method) {} + + /** {@inheritDoc} */ public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, Node annotationNode, Annotation annotation) {} + + /** {@inheritDoc} */ public void endVisitMethodArgument(Node argNode, Argument arg, AbstractMethodDeclaration method) {} + + /** {@inheritDoc} */ public void visitLocal(Node localNode, LocalDeclaration local) {} + + /** {@inheritDoc} */ public void visitAnnotationOnLocal(LocalDeclaration local, Node annotationNode, Annotation annotation) {} + + /** {@inheritDoc} */ public void endVisitLocal(Node localNode, LocalDeclaration local) {} + + /** {@inheritDoc} */ public void visitStatement(Node statementNode, Statement statement) {} + + /** {@inheritDoc} */ public void endVisitStatement(Node statementNode, Statement statement) {} } diff --git a/src/lombok/eclipse/EclipseASTVisitor.java b/src/lombok/eclipse/EclipseASTVisitor.java index 49a8696b..ac4ed238 100644 --- a/src/lombok/eclipse/EclipseASTVisitor.java +++ b/src/lombok/eclipse/EclipseASTVisitor.java @@ -1,7 +1,26 @@ +/* + * Copyright © 2009 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.eclipse; -import java.io.File; -import java.io.FileNotFoundException; import java.io.PrintStream; import java.lang.reflect.Modifier; @@ -20,7 +39,10 @@ import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; -//TODO expand javadoc +/** + * Implement so you can ask any JavacAST.Node to traverse depth-first through all children, + * calling the appropriate visit and endVisit methods. + */ public interface EclipseASTVisitor { /** * Called at the very beginning and end. @@ -82,20 +104,30 @@ public interface EclipseASTVisitor { void visitStatement(Node statementNode, Statement statement); void endVisitStatement(Node statementNode, Statement statement); + /** + * Prints the structure of an AST. + */ public static class Printer implements EclipseASTVisitor { private final PrintStream out; private final boolean printContent; private int disablePrinting = 0; private int indent = 0; + /** + * @param printContent if true, method and initializer bodies are printed directly, as java code, + * instead of a tree listing of every AST node inside it. + */ public Printer(boolean printContent) { this(printContent, System.out); } - public Printer(boolean printContent, File file) throws FileNotFoundException { - this(printContent, new PrintStream(file)); - } - + /** + * @param printContent if true, method and initializer bodies are printed directly, as java code, + * instead of a tree listing of every AST node inside it. + * @param PrintStream write output to this stream. You must close it yourself. flush() is called after every line. + * + * @see java.io.PrintStream#flush() + */ public Printer(boolean printContent, PrintStream out) { this.printContent = printContent; this.out = out; diff --git a/src/lombok/eclipse/EclipseAnnotationHandler.java b/src/lombok/eclipse/EclipseAnnotationHandler.java index e94607f6..39e4d3df 100644 --- a/src/lombok/eclipse/EclipseAnnotationHandler.java +++ b/src/lombok/eclipse/EclipseAnnotationHandler.java @@ -1,7 +1,54 @@ +/* + * Copyright © 2009 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.eclipse; import lombok.core.AnnotationValues; +/** + * Implement this interface if you want to be triggered for a specific annotation. + * + * You MUST replace 'T' with a specific annotation type, such as: + * + * <code>public class HandleGetter implements EclipseAnnotationHandler<<b>Getter</b>></code> + * + * Because this generics parameter is inspected to figure out which class you're interested in. + * + * You also need to register yourself via SPI discovery as being an implementation of <code>EclipseAnnotationHandler</code>. + */ public interface EclipseAnnotationHandler<T extends java.lang.annotation.Annotation> { + /** + * Called when an annotation is found that is likely to match the annotation you're interested in. + * + * Be aware that you'll be called for ANY annotation node in the source that looks like a match. There is, + * for example, no guarantee that the annotation node belongs to a method, even if you set your + * TargetType in the annotation to methods only. + * + * @param annotation The actual annotation - use this object to retrieve the annotation parameters. + * @param ast The eclipse AST node representing the annotation. + * @param annotationNode The Lombok AST wrapper around the 'ast' parameter. You can use this object + * to travel back up the chain (something javac AST can't do) to the parent of the annotation, as well + * as access useful methods such as generating warnings or errors focused on the annotation. + * @return <code>true</code> if you don't want to be called again about this annotation during this + * compile session (you've handled it), or <code>false</code> to indicate you aren't done yet. + */ boolean handle(AnnotationValues<T> annotation, org.eclipse.jdt.internal.compiler.ast.Annotation ast, EclipseAST.Node annotationNode); } diff --git a/src/lombok/eclipse/HandlerLibrary.java b/src/lombok/eclipse/HandlerLibrary.java index 6ee2baaa..b319f580 100644 --- a/src/lombok/eclipse/HandlerLibrary.java +++ b/src/lombok/eclipse/HandlerLibrary.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse; import static lombok.eclipse.Eclipse.toQualifiedName; @@ -21,7 +42,19 @@ import lombok.eclipse.EclipseAST.Node; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +/** + * This class tracks 'handlers' and knows how to invoke them for any given AST node. + * + * This class can find the handlers (via SPI discovery) and will set up the given AST node, such as + * building an AnnotationValues instance. + */ public class HandlerLibrary { + /** + * Creates a new HandlerLibrary. Errors will be reported to the eclipse Error log. + * You probably want to use {@link #load()} instead. + */ + public HandlerLibrary() {} + private TypeLibrary typeLibrary = new TypeLibrary(); private static class AnnotationHandlerContainer<T extends Annotation> { @@ -47,6 +80,11 @@ public class HandlerLibrary { private boolean skipPrintAST; + /** + * Creates a new HandlerLibrary. Errors will be reported to the eclipse Error log. + * then uses SPI discovery to load all annotation and visitor based handlers so that future calls + * to the handle methods will defer to these handlers. + */ public static HandlerLibrary load() { HandlerLibrary lib = new HandlerLibrary(); @@ -56,6 +94,7 @@ public class HandlerLibrary { return lib; } + /** Uses SPI Discovery to find implementations of {@link EclipseAnnotationHandler}. */ @SuppressWarnings("unchecked") private static void loadAnnotationHandlers(HandlerLibrary lib) { Iterator<EclipseAnnotationHandler> it; try { @@ -80,6 +119,7 @@ public class HandlerLibrary { } } + /** Uses SPI Discovery to find implementations of {@link EclipseASTVisitor}. */ private static void loadVisitorHandlers(HandlerLibrary lib) { Iterator<EclipseASTVisitor> it; try { @@ -96,6 +136,23 @@ public class HandlerLibrary { } } + /** + * Handles the provided annotation node by first finding a qualifying instance of + * {@link EclipseAnnotationHandler} and if one exists, calling it with a freshly cooked up + * instance of {@link AnnotationValues}. + * + * Note that depending on the printASTOnly flag, the {@link lombok.core.PrintAST} annotation + * will either be silently skipped, or everything that isn't <code>PrintAST</code> will be skipped. + * + * The HandlerLibrary will attempt to guess if the given annotation node represents a lombok annotation. + * For example, if <code>lombok.*</code> is in the import list, then this method will guess that + * <code>Getter</code> refers to <code>lombok.Getter</code>, presuming that {@link lombok.javac.handlers.HandleGetter} + * has been loaded. + * + * @param unit The Compilation Unit that contains the Annotation AST Node. + * @param node The Lombok AST Node representing the Annotation AST Node. + * @param annotation 'node.get()' - convenience parameter. + */ public boolean handle(CompilationUnitDeclaration ast, EclipseAST.Node annotationNode, org.eclipse.jdt.internal.compiler.ast.Annotation annotation) { String pkgName = annotationNode.getPackageDeclaration(); @@ -124,6 +181,9 @@ public class HandlerLibrary { return handled; } + /** + * Will call all registered {@link EclipseASTVisitor} instances. + */ public void callASTVisitors(EclipseAST ast) { for ( EclipseASTVisitor visitor : visitorHandlers ) try { ast.traverse(visitor); @@ -133,10 +193,18 @@ public class HandlerLibrary { } } + /** + * Lombok does not currently support triggering annotations in a specified order; the order is essentially + * random right now. This lack of order is particularly annoying for the <code>PrintAST</code> annotation, + * which is almost always intended to run last. Hence, this hack, which lets it in fact run last. + * + * {@see #skipAllButPrintAST} + */ public void skipPrintAST() { skipPrintAST = true; } + /** {@see #skipPrintAST} */ public void skipAllButPrintAST() { skipPrintAST = false; } diff --git a/src/lombok/eclipse/TransformEclipseAST.java b/src/lombok/eclipse/TransformEclipseAST.java index 66d663f4..f7a4c715 100644 --- a/src/lombok/eclipse/TransformEclipseAST.java +++ b/src/lombok/eclipse/TransformEclipseAST.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse; import java.lang.reflect.Field; @@ -102,6 +123,10 @@ public class TransformEclipseAST { this.ast = ast; } + /** + * First handles all lombok annotations except PrintAST, then calls all non-annotation based handlers. + * then handles any PrintASTs. + */ public void go() { handlers.skipPrintAST(); ast.traverse(new AnnotationVisitor()); diff --git a/src/lombok/eclipse/handlers/HandleCleanup.java b/src/lombok/eclipse/handlers/HandleCleanup.java index b5251e8a..29f1ec7c 100644 --- a/src/lombok/eclipse/handlers/HandleCleanup.java +++ b/src/lombok/eclipse/handlers/HandleCleanup.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import java.util.Arrays; @@ -24,6 +45,9 @@ import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.mangosdk.spi.ProviderFor; +/** + * Handles the <code>lombok.Cleanup</code> annotation for javac. + */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleCleanup implements EclipseAnnotationHandler<Cleanup> { public boolean handle(AnnotationValues<Cleanup> annotation, Annotation ast, Node annotationNode) { diff --git a/src/lombok/eclipse/handlers/HandleData.java b/src/lombok/eclipse/handlers/HandleData.java index 84db0df1..c7f053e6 100644 --- a/src/lombok/eclipse/handlers/HandleData.java +++ b/src/lombok/eclipse/handlers/HandleData.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import static lombok.eclipse.Eclipse.*; @@ -67,6 +88,9 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.mangosdk.spi.ProviderFor; +/** + * Handles the <code>lombok.Data</code> annotation for javac. + */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleData implements EclipseAnnotationHandler<Data> { public boolean handle(AnnotationValues<Data> annotation, Annotation ast, Node annotationNode) { diff --git a/src/lombok/eclipse/handlers/HandleGetter.java b/src/lombok/eclipse/handlers/HandleGetter.java index 159b49fd..78b399c5 100644 --- a/src/lombok/eclipse/handlers/HandleGetter.java +++ b/src/lombok/eclipse/handlers/HandleGetter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import static lombok.eclipse.handlers.PKG.*; @@ -23,8 +44,23 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.mangosdk.spi.ProviderFor; +/** + * Handles the <code>lombok.Getter</code> annotation for javac. + */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleGetter implements EclipseAnnotationHandler<Getter> { + /** + * Generates a getter on the stated field. + * + * Used by {@link HandleData}. + * + * The difference between this call and the handle method is as follows: + * + * If there is a <code>lombok.Getter</code> annotation on the field, it is used and the + * same rules apply (e.g. warning if the method already exists, stated access level applies). + * If not, the getter is still generated if it isn't already there, though there will not + * be a warning if its already there. The default access level is used. + */ public void generateGetterForField(Node fieldNode, ASTNode pos) { AccessLevel level = AccessLevel.PUBLIC; Node errorNode = fieldNode; diff --git a/src/lombok/eclipse/handlers/HandlePrintAST.java b/src/lombok/eclipse/handlers/HandlePrintAST.java index a2ccad77..2b06fbe4 100644 --- a/src/lombok/eclipse/handlers/HandlePrintAST.java +++ b/src/lombok/eclipse/handlers/HandlePrintAST.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import java.io.File; @@ -14,6 +35,9 @@ import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseAST.Node; +/** + * Handles the <code>lombok.core.PrintAST</code> annotation for javac. + */ @ProviderFor(EclipseAnnotationHandler.class) public class HandlePrintAST implements EclipseAnnotationHandler<PrintAST> { public boolean handle(AnnotationValues<PrintAST> annotation, Annotation ast, Node annotationNode) { diff --git a/src/lombok/eclipse/handlers/HandleSetter.java b/src/lombok/eclipse/handlers/HandleSetter.java index 57dabc03..70eb855e 100644 --- a/src/lombok/eclipse/handlers/HandleSetter.java +++ b/src/lombok/eclipse/handlers/HandleSetter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import static lombok.eclipse.handlers.PKG.*; @@ -27,8 +48,23 @@ import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.mangosdk.spi.ProviderFor; +/** + * Handles the <code>lombok.Setter</code> annotation for javac. + */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleSetter implements EclipseAnnotationHandler<Setter> { + /** + * Generates a setter on the stated field. + * + * Used by {@link HandleData}. + * + * The difference between this call and the handle method is as follows: + * + * If there is a <code>lombok.Setter</code> annotation on the field, it is used and the + * same rules apply (e.g. warning if the method already exists, stated access level applies). + * If not, the setter is still generated if it isn't already there, though there will not + * be a warning if its already there. The default access level is used. + */ public void generateSetterForField(Node fieldNode, ASTNode pos) { AccessLevel level = AccessLevel.PUBLIC; Node errorNode = fieldNode; diff --git a/src/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/lombok/eclipse/handlers/HandleSneakyThrows.java index 01b00efb..8126944d 100644 --- a/src/lombok/eclipse/handlers/HandleSneakyThrows.java +++ b/src/lombok/eclipse/handlers/HandleSneakyThrows.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import java.util.ArrayList; @@ -27,6 +48,9 @@ import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.mangosdk.spi.ProviderFor; +/** + * Handles the <code>lombok.HandleSneakyThrows</code> annotation for javac. + */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleSneakyThrows implements EclipseAnnotationHandler<SneakyThrows> { private static class DeclaredException { diff --git a/src/lombok/eclipse/handlers/HandleSynchronized.java b/src/lombok/eclipse/handlers/HandleSynchronized.java index e1d4ed6a..9290990b 100644 --- a/src/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/lombok/eclipse/handlers/HandleSynchronized.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import static lombok.eclipse.handlers.PKG.*; @@ -27,6 +48,9 @@ import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.mangosdk.spi.ProviderFor; +/** + * Handles the <code>lombok.Synchronized</code> annotation for javac. + */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleSynchronized implements EclipseAnnotationHandler<Synchronized> { private static final char[] INSTANCE_LOCK_NAME = "$lock".toCharArray(); @@ -49,9 +73,17 @@ public class HandleSynchronized implements EclipseAnnotationHandler<Synchronized } char[] lockName = annotation.getInstance().value().toCharArray(); - if ( lockName.length == 0 ) lockName = method.isStatic() ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; + boolean autoMake = false; + if ( lockName.length == 0 ) { + autoMake = true; + lockName = method.isStatic() ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; + } if ( fieldExists(new String(lockName), methodNode) == MemberExistsResult.NOT_EXISTS ) { + if ( !autoMake ) { + annotationNode.addError("The field " + new String(lockName) + " does not exist."); + return true; + } FieldDeclaration fieldDecl = new FieldDeclaration(lockName, 0, -1); fieldDecl.declarationSourceEnd = -1; diff --git a/src/lombok/eclipse/handlers/PKG.java b/src/lombok/eclipse/handlers/PKG.java index 697514a7..7fdf7afd 100644 --- a/src/lombok/eclipse/handlers/PKG.java +++ b/src/lombok/eclipse/handlers/PKG.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.eclipse.handlers; import java.lang.reflect.Modifier; diff --git a/src/lombok/javac/JavacAST.java b/src/lombok/javac/JavacAST.java index 4eecbc68..c68d3c19 100644 --- a/src/lombok/javac/JavacAST.java +++ b/src/lombok/javac/JavacAST.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import java.lang.reflect.Field; @@ -30,6 +51,10 @@ import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +/** + * Wraps around javac's internal AST view to add useful features as well as the ability to visit parents from children, + * something javac's own AST system does not offer. + */ public class JavacAST extends AST<JCTree> { private final Messager messager; private final Name.Table nameTable; @@ -37,6 +62,14 @@ public class JavacAST extends AST<JCTree> { private final Symtab symtab; private final Log log; + /** + * Creates a new JavacAST of the provided Compilation Unit. + * + * @param trees The trees instance to use to inspect the compilation unit. Generate via: + * <code>Trees.getInstance(env)</code> + * @param env The ProcessingEnvironment object passed e.g. to an annotation processor. + * @param top The compilation unit, which serves as the top level node in the tree to be built. + */ public JavacAST(Trees trees, JavacProcessingEnvironment env, JCCompilationUnit top) { super(top.sourcefile == null ? null : top.sourcefile.toString()); setTop(buildCompilationUnit(top)); @@ -47,11 +80,13 @@ public class JavacAST extends AST<JCTree> { this.symtab = Symtab.instance(env.getContext()); } + /** {@inheritDoc} */ @Override public String getPackageDeclaration() { JCCompilationUnit unit = (JCCompilationUnit)top().get(); return unit.pid instanceof JCFieldAccess ? unit.pid.toString() : null; } + /** {@inheritDoc} */ @Override public Collection<String> getImportStatements() { List<String> imports = new ArrayList<String>(); JCCompilationUnit unit = (JCCompilationUnit)top().get(); @@ -64,6 +99,10 @@ public class JavacAST extends AST<JCTree> { return imports; } + /** + * Runs through the entire AST, starting at the compilation unit, calling the provided visitor's visit methods + * for each node, depth first. + */ public void traverse(JavacASTVisitor visitor) { top().traverse(visitor); } @@ -74,26 +113,32 @@ public class JavacAST extends AST<JCTree> { } } + /** {@inheritDoc} */ @Override public Node top() { return (Node) super.top(); } + /** {@inheritDoc} */ @Override public Node get(JCTree astNode) { return (Node) super.get(astNode); } + /** @return A Name object generated for the proper name table belonging to this AST. */ public Name toName(String name) { return nameTable.fromString(name); } + /** @return A TreeMaker instance that you can use to create new AST nodes. */ public TreeMaker getTreeMaker() { return treeMaker; } + /** @return The symbol table used by this AST for symbols. */ public Symtab getSymbolTable() { return symtab; } + /** {@inheritDoc} */ @Override protected Node buildTree(JCTree node, Kind kind) { switch ( kind ) { case COMPILATION_UNIT: @@ -214,6 +259,7 @@ public class JavacAST extends AST<JCTree> { return putInMap(new Node(statement, childNodes, Kind.STATEMENT)); } + /** For javac, both JCExpression and JCStatement are considered as valid children types. */ protected Collection<Class<? extends JCTree>> getStatementTypes() { Collection<Class<? extends JCTree>> collection = new ArrayList<Class<? extends JCTree>>(2); collection.add(JCStatement.class); @@ -225,11 +271,20 @@ public class JavacAST extends AST<JCTree> { if ( node != null ) nodes.add(node); } + /** + * Javac specific version of the AST.Node class. + */ public class Node extends AST<JCTree>.Node { + /** + * See the {@link AST.Node} constructor for information. + */ public Node(JCTree node, List<Node> children, Kind kind) { super(node, children, kind); } + /** + * Visits this node and all child nodes depth-first, calling the provided visitor's visit methods. + */ public void traverse(JavacASTVisitor visitor) { switch ( this.getKind() ) { case COMPILATION_UNIT: @@ -301,6 +356,7 @@ public class JavacAST extends AST<JCTree> { } } + /** {@inheritDoc} */ @Override public String getName() { final Name n; @@ -312,6 +368,7 @@ public class JavacAST extends AST<JCTree> { return n == null ? null : n.toString(); } + /** {@inheritDoc} */ @Override protected boolean calculateIsStructurallySignificant() { if ( node instanceof JCClassDecl ) return true; if ( node instanceof JCMethodDecl ) return true; @@ -320,14 +377,29 @@ public class JavacAST extends AST<JCTree> { return false; } + /** + * Convenient shortcut to the owning JavacAST object's getTreeMaker method. + * + * @see JavacAST#getTreeMaker() + */ public TreeMaker getTreeMaker() { return treeMaker; } + /** + * Convenient shortcut to the owning JavacAST object's getSymbolTable method. + * + * @see JavacAST#getSymbolTable() + */ public Symtab getSymbolTable() { return symtab; } + /** + * Convenient shortcut to the owning JavacAST object's toName method. + * + * @see JavacAST#toName(String) + */ public Name toName(String name) { return JavacAST.this.toName(name); } @@ -358,18 +430,30 @@ public class JavacAST extends AST<JCTree> { return (Collection<Node>) super.down(); } + /** + * Generates an compiler error focused on the AST node represented by this node object. + */ public void addError(String message) { printMessage(Diagnostic.Kind.ERROR, message, this, null); } + /** + * Generates an compiler error focused on the AST node represented by this node object. + */ public void addError(String message, DiagnosticPosition pos) { printMessage(Diagnostic.Kind.ERROR, message, null, pos); } + /** + * Generates a compiler warning focused on the AST node represented by this node object. + */ public void addWarning(String message) { printMessage(Diagnostic.Kind.WARNING, message, this, null); } + /** + * Generates a compiler warning focused on the AST node represented by this node object. + */ public void addWarning(String message, DiagnosticPosition pos) { printMessage(Diagnostic.Kind.WARNING, message, null, pos); } @@ -409,6 +493,7 @@ public class JavacAST extends AST<JCTree> { } } + /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override protected void setElementInASTCollection(Field field, Object refField, List<Collection<?>> chain, Collection<?> collection, int idx, JCTree newN) throws IllegalAccessException { com.sun.tools.javac.util.List<?> list = setElementInConsList(chain, collection, ((List)collection).get(idx), newN); @@ -439,7 +524,7 @@ public class JavacAST extends AST<JCTree> { if ( repl ) return com.sun.tools.javac.util.List.<Object>from(a); else return oldL; } - + private void increaseErrorCount(Messager messager) { try { Field f = messager.getClass().getDeclaredField("errorCount"); diff --git a/src/lombok/javac/JavacASTAdapter.java b/src/lombok/javac/JavacASTAdapter.java index 5d678f44..b720ea32 100644 --- a/src/lombok/javac/JavacASTAdapter.java +++ b/src/lombok/javac/JavacASTAdapter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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; import lombok.javac.JavacAST.Node; @@ -10,26 +31,70 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +/** + * Standard adapter for the {@link JavacASTVisitor} interface. Every method on that interface + * has been implemented with an empty body. Override whichever methods you need. + */ public class JavacASTAdapter implements JavacASTVisitor { + /** {@inheritDoc} */ @Override public void visitCompilationUnit(Node top, JCCompilationUnit unit) {} + + /** {@inheritDoc} */ @Override public void endVisitCompilationUnit(Node top, JCCompilationUnit unit) {} + + /** {@inheritDoc} */ @Override public void visitType(Node typeNode, JCClassDecl type) {} + + /** {@inheritDoc} */ @Override public void visitAnnotationOnType(JCClassDecl type, Node annotationNode, JCAnnotation annotation) {} + + /** {@inheritDoc} */ @Override public void endVisitType(Node typeNode, JCClassDecl type) {} + + /** {@inheritDoc} */ @Override public void visitField(Node fieldNode, JCVariableDecl field) {} + + /** {@inheritDoc} */ @Override public void visitAnnotationOnField(JCVariableDecl field, Node annotationNode, JCAnnotation annotation) {} + + /** {@inheritDoc} */ @Override public void endVisitField(Node fieldNode, JCVariableDecl field) {} + + /** {@inheritDoc} */ @Override public void visitInitializer(Node initializerNode, JCBlock initializer) {} + + /** {@inheritDoc} */ @Override public void endVisitInitializer(Node initializerNode, JCBlock initializer) {} + + /** {@inheritDoc} */ @Override public void visitMethod(Node methodNode, JCMethodDecl method) {} + + /** {@inheritDoc} */ @Override public void visitAnnotationOnMethod(JCMethodDecl method, Node annotationNode, JCAnnotation annotation) {} + + /** {@inheritDoc} */ @Override public void endVisitMethod(Node methodNode, JCMethodDecl method) {} + + /** {@inheritDoc} */ @Override public void visitMethodArgument(Node argumentNode, JCVariableDecl argument, JCMethodDecl method) {} + + /** {@inheritDoc} */ @Override public void visitAnnotationOnMethodArgument(JCVariableDecl argument, JCMethodDecl method, Node annotationNode, JCAnnotation annotation) {} + /** {@inheritDoc} */ @Override public void endVisitMethodArgument(Node argumentNode, JCVariableDecl argument, JCMethodDecl method) {} + + /** {@inheritDoc} */ @Override public void visitLocal(Node localNode, JCVariableDecl local) {} + + /** {@inheritDoc} */ @Override public void visitAnnotationOnLocal(JCVariableDecl local, Node annotationNode, JCAnnotation annotation) {} + + /** {@inheritDoc} */ @Override public void endVisitLocal(Node localNode, JCVariableDecl local) {} + + /** {@inheritDoc} */ @Override public void visitStatement(Node statementNode, JCTree statement) {} + + /** {@inheritDoc} */ @Override public void endVisitStatement(Node statementNode, JCTree statement) {} } diff --git a/src/lombok/javac/JavacASTVisitor.java b/src/lombok/javac/JavacASTVisitor.java index 15d848dd..ac953974 100644 --- a/src/lombok/javac/JavacASTVisitor.java +++ b/src/lombok/javac/JavacASTVisitor.java @@ -1,7 +1,26 @@ +/* + * Copyright © 2009 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; -import java.io.File; -import java.io.FileNotFoundException; import java.io.PrintStream; import lombok.javac.JavacAST.Node; @@ -15,6 +34,10 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +/** + * Implement so you can ask any JavacAST.Node to traverse depth-first through all children, + * calling the appropriate visit and endVisit methods. + */ public interface JavacASTVisitor { /** * Called at the very beginning and end. @@ -71,20 +94,30 @@ public interface JavacASTVisitor { void visitStatement(Node statementNode, JCTree statement); void endVisitStatement(Node statementNode, JCTree statement); + /** + * Prints the structure of an AST. + */ public static class Printer implements JavacASTVisitor { private final PrintStream out; private final boolean printContent; private int disablePrinting = 0; private int indent = 0; + /** + * @param printContent if true, method and initializer bodies are printed directly, as java code, + * instead of a tree listing of every AST node inside it. + */ public Printer(boolean printContent) { this(printContent, System.out); } - public Printer(boolean printContent, File file) throws FileNotFoundException { - this(printContent, new PrintStream(file)); - } - + /** + * @param printContent if true, method and initializer bodies are printed directly, as java code, + * instead of a tree listing of every AST node inside it. + * @param PrintStream write output to this stream. You must close it yourself. flush() is called after every line. + * + * @see java.io.PrintStream#flush() + */ public Printer(boolean printContent, PrintStream out) { this.printContent = printContent; this.out = out; diff --git a/src/lombok/javac/JavacAnnotationHandler.java b/src/lombok/javac/JavacAnnotationHandler.java index 65832eab..fcd0cbba 100644 --- a/src/lombok/javac/JavacAnnotationHandler.java +++ b/src/lombok/javac/JavacAnnotationHandler.java @@ -50,7 +50,7 @@ public interface JavacAnnotationHandler<T extends Annotation> { * @param ast The javac AST node representing the annotation. * @param annotationNode The Lombok AST wrapper around the 'ast' parameter. You can use this object * to travel back up the chain (something javac AST can't do) to the parent of the annotation, as well - * as access useful methods such as generating warnings or errors focussed on the annotation. + * as access useful methods such as generating warnings or errors focused on the annotation. * @return <code>true</code> if you don't want to be called again about this annotation during this * compile session (you've handled it), or <code>false</code> to indicate you aren't done yet. */ diff --git a/src/lombok/javac/apt/Processor.java b/src/lombok/javac/apt/Processor.java index 7bffd33e..22daeab1 100644 --- a/src/lombok/javac/apt/Processor.java +++ b/src/lombok/javac/apt/Processor.java @@ -66,6 +66,7 @@ public class Processor extends AbstractProcessor { private HandlerLibrary handlers; private Trees trees; + /** {@inheritDoc} */ @Override public void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); if ( !(processingEnv instanceof JavacProcessingEnvironment) ) this.processingEnv = null; @@ -76,6 +77,7 @@ public class Processor extends AbstractProcessor { } } + /** {@inheritDoc} */ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if ( processingEnv == null ) return false; diff --git a/src/lombok/javac/handlers/HandleCleanup.java b/src/lombok/javac/handlers/HandleCleanup.java index 39f2c242..04ed2ed6 100644 --- a/src/lombok/javac/handlers/HandleCleanup.java +++ b/src/lombok/javac/handlers/HandleCleanup.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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.Cleanup; @@ -26,6 +47,9 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; +/** + * Handles the <code>lombok.Cleanup</code> annotation for javac. + */ @ProviderFor(JavacAnnotationHandler.class) public class HandleCleanup implements JavacAnnotationHandler<Cleanup> { @Override public boolean handle(AnnotationValues<Cleanup> annotation, JCAnnotation ast, Node annotationNode) { diff --git a/src/lombok/javac/handlers/HandleData.java b/src/lombok/javac/handlers/HandleData.java index 5da08759..d3974c58 100644 --- a/src/lombok/javac/handlers/HandleData.java +++ b/src/lombok/javac/handlers/HandleData.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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 java.lang.reflect.Modifier; @@ -37,6 +58,9 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; +/** + * Handles the <code>lombok.Data</code> annotation for javac. + */ @ProviderFor(JavacAnnotationHandler.class) public class HandleData implements JavacAnnotationHandler<Data> { @Override public boolean handle(AnnotationValues<Data> annotation, JCAnnotation ast, Node annotationNode) { diff --git a/src/lombok/javac/handlers/HandleGetter.java b/src/lombok/javac/handlers/HandleGetter.java index f66247ff..18e02a58 100644 --- a/src/lombok/javac/handlers/HandleGetter.java +++ b/src/lombok/javac/handlers/HandleGetter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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 static lombok.javac.handlers.PKG.*; @@ -24,8 +45,23 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +/** + * Handles the <code>lombok.Getter</code> annotation for javac. + */ @ProviderFor(JavacAnnotationHandler.class) public class HandleGetter implements JavacAnnotationHandler<Getter> { + /** + * Generates a getter on the stated field. + * + * Used by {@link HandleData}. + * + * The difference between this call and the handle method is as follows: + * + * If there is a <code>lombok.Getter</code> annotation on the field, it is used and the + * same rules apply (e.g. warning if the method already exists, stated access level applies). + * If not, the getter is still generated if it isn't already there, though there will not + * be a warning if its already there. The default access level is used. + */ public void generateGetterForField(Node fieldNode, DiagnosticPosition pos) { AccessLevel level = AccessLevel.PUBLIC; Node errorNode = fieldNode; diff --git a/src/lombok/javac/handlers/HandlePrintAST.java b/src/lombok/javac/handlers/HandlePrintAST.java index f2009c71..aa7b0ab9 100644 --- a/src/lombok/javac/handlers/HandlePrintAST.java +++ b/src/lombok/javac/handlers/HandlePrintAST.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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 java.io.File; @@ -15,6 +36,9 @@ import lombok.javac.JavacASTVisitor; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacAST.Node; +/** + * Handles the <code>lombok.core.PrintAST</code> annotation for javac. + */ @ProviderFor(JavacAnnotationHandler.class) public class HandlePrintAST implements JavacAnnotationHandler<PrintAST> { @Override public boolean handle(AnnotationValues<PrintAST> annotation, JCAnnotation ast, Node annotationNode) { diff --git a/src/lombok/javac/handlers/HandleSetter.java b/src/lombok/javac/handlers/HandleSetter.java index 2b766db1..817d3011 100644 --- a/src/lombok/javac/handlers/HandleSetter.java +++ b/src/lombok/javac/handlers/HandleSetter.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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 static lombok.javac.handlers.PKG.*; @@ -27,8 +48,23 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +/** + * Handles the <code>lombok.Setter</code> annotation for javac. + */ @ProviderFor(JavacAnnotationHandler.class) public class HandleSetter implements JavacAnnotationHandler<Setter> { + /** + * Generates a setter on the stated field. + * + * Used by {@link HandleData}. + * + * The difference between this call and the handle method is as follows: + * + * If there is a <code>lombok.Setter</code> annotation on the field, it is used and the + * same rules apply (e.g. warning if the method already exists, stated access level applies). + * If not, the setter is still generated if it isn't already there, though there will not + * be a warning if its already there. The default access level is used. + */ public void generateSetterForField(Node fieldNode, DiagnosticPosition pos) { AccessLevel level = AccessLevel.PUBLIC; Node errorNode = fieldNode; diff --git a/src/lombok/javac/handlers/HandleSneakyThrows.java b/src/lombok/javac/handlers/HandleSneakyThrows.java index b21468ee..4a4ab09b 100644 --- a/src/lombok/javac/handlers/HandleSneakyThrows.java +++ b/src/lombok/javac/handlers/HandleSneakyThrows.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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 static lombok.javac.handlers.PKG.chainDots; @@ -24,6 +45,9 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; +/** + * Handles the <code>lombok.SneakyThrows</code> annotation for javac. + */ @ProviderFor(JavacAnnotationHandler.class) public class HandleSneakyThrows implements JavacAnnotationHandler<SneakyThrows> { @Override public boolean handle(AnnotationValues<SneakyThrows> annotation, JCAnnotation ast, Node annotationNode) { diff --git a/src/lombok/javac/handlers/HandleSynchronized.java b/src/lombok/javac/handlers/HandleSynchronized.java index 84508171..efc6daf0 100644 --- a/src/lombok/javac/handlers/HandleSynchronized.java +++ b/src/lombok/javac/handlers/HandleSynchronized.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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 static lombok.javac.handlers.PKG.*; @@ -21,6 +42,9 @@ import lombok.core.AST.Kind; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacAST.Node; +/** + * Handles the <code>lombok.Synchronized</code> annotation for javac. + */ @ProviderFor(JavacAnnotationHandler.class) public class HandleSynchronized implements JavacAnnotationHandler<Synchronized> { private static final String INSTANCE_LOCK_NAME = "$lock"; @@ -42,11 +66,19 @@ public class HandleSynchronized implements JavacAnnotationHandler<Synchronized> } boolean isStatic = (method.mods.flags & Flags.STATIC) != 0; String lockName = annotation.getInstance().value(); - if ( lockName.length() == 0 ) lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; + boolean autoMake = false; + if ( lockName.length() == 0 ) { + autoMake = true; + lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; + } TreeMaker maker = methodNode.getTreeMaker(); if ( fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS ) { + if ( !autoMake ) { + annotationNode.addError("The field " + new String(lockName) + " does not exist."); + return true; + } JCExpression objectType = chainDots(maker, methodNode, "java", "lang", "Object"); //We use 'new Object[0];' because quite unlike 'new Object();', empty arrays *ARE* serializable! JCNewArray newObjectArray = maker.NewArray(chainDots(maker, methodNode, "java", "lang", "Object"), diff --git a/src/lombok/javac/handlers/PKG.java b/src/lombok/javac/handlers/PKG.java index b7a02985..ef6b3eba 100644 --- a/src/lombok/javac/handlers/PKG.java +++ b/src/lombok/javac/handlers/PKG.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 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 java.lang.reflect.Modifier; @@ -16,9 +37,17 @@ import lombok.core.TransformationsUtil; import lombok.core.AST.Kind; import lombok.javac.JavacAST; +/** + * Container for static utility methods relevant to this package. + */ class PKG { - private PKG() {} + private PKG() { + //Prevent instantiation + } + /** + * @return the likely getter name for the stated field. (e.g. private boolean foo; to isFoo). + */ static String toGetterName(JCVariableDecl field) { CharSequence fieldName = field.name; @@ -27,16 +56,26 @@ class PKG { return TransformationsUtil.toGetterName(fieldName, isBoolean); } + /** + * @return the likely setter name for the stated field. (e.g. private boolean foo; to setFoo). + */ static String toSetterName(JCVariableDecl field) { CharSequence fieldName = field.name; return TransformationsUtil.toSetterName(fieldName); } + /** Serves as return value for the methods that check for the existence of fields and methods. */ enum MemberExistsResult { NOT_EXISTS, EXISTS_BY_USER, EXISTS_BY_LOMBOK; } + /** + * Checks if there is a field with the provided name. + * + * @param fieldName the field name to check for. + * @param node Any node that represents the Type (JCClassDecl) to check for, or any child node thereof. + */ static MemberExistsResult fieldExists(String fieldName, JavacAST.Node node) { while ( node != null && !(node.get() instanceof JCClassDecl) ) { node = node.up(); @@ -57,6 +96,13 @@ class PKG { return MemberExistsResult.NOT_EXISTS; } + /** + * Checks if there is a method with the provided name. In case of multiple methods (overloading), only + * the first method decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned. + * + * @param methodName the method name to check for. + * @param node Any node that represents the Type (JCClassDecl) to check for, or any child node thereof. + */ static MemberExistsResult methodExists(String methodName, JavacAST.Node node) { while ( node != null && !(node.get() instanceof JCClassDecl) ) { node = node.up(); @@ -77,6 +123,12 @@ class PKG { return MemberExistsResult.NOT_EXISTS; } + /** + * Checks if there is a (non-default) constructor. In case of multiple constructors (overloading), only + * the first constructor decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned. + * + * @param node Any node that represents the Type (JCClassDecl) to check for, or any child node thereof. + */ static MemberExistsResult constructorExists(JavacAST.Node node) { while ( node != null && !(node.get() instanceof JCClassDecl) ) { node = node.up(); @@ -98,6 +150,11 @@ class PKG { return MemberExistsResult.NOT_EXISTS; } + /** + * Turns an <code>AccessLevel<code> instance into the flag bit used by javac. + * + * @see java.lang.Modifier + */ static int toJavacModifier(AccessLevel accessLevel) { switch ( accessLevel ) { case MODULE: @@ -113,6 +170,11 @@ class PKG { } } + /** + * Adds the given new field declaration to the provided type AST Node. + * + * Also takes care of updating the JavacAST. + */ static void injectField(JavacAST.Node typeNode, JCVariableDecl field) { JCClassDecl type = (JCClassDecl) typeNode.get(); @@ -121,6 +183,12 @@ class PKG { typeNode.add(field, Kind.FIELD).recursiveSetHandled(); } + /** + * Adds the given new method declaration to the provided type AST Node. + * Can also inject constructors. + * + * Also takes care of updating the JavacAST. + */ static void injectMethod(JavacAST.Node typeNode, JCMethodDecl method) { JCClassDecl type = (JCClassDecl) typeNode.get(); @@ -154,6 +222,16 @@ class PKG { return out; } + /** + * In javac, dotted access of any kind, from <code>java.lang.String</code> to <code>var.methodName</code> + * is represented by a fold-left of <code>Select</code> nodes with the leftmost string represented by + * a <code>Ident</code> 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 + */ static JCExpression chainDots(TreeMaker maker, JavacAST.Node node, String... elems) { assert elems != null; assert elems.length > 0; |