diff options
Diffstat (limited to 'src')
49 files changed, 2047 insertions, 1998 deletions
diff --git a/src/lombok/Lombok.java b/src/lombok/Lombok.java index 9656b7fd..f2f196ed 100644 --- a/src/lombok/Lombok.java +++ b/src/lombok/Lombok.java @@ -48,7 +48,7 @@ public class Lombok { * @return A dummy RuntimeException; this method never returns normally, it <em>always</em> throws an exception! */ public static RuntimeException sneakyThrow(Throwable t) { - if ( t == null ) throw new NullPointerException("t"); + if (t == null) throw new NullPointerException("t"); Lombok.<RuntimeException>sneakyThrow0(t); return null; } diff --git a/src/lombok/core/AST.java b/src/lombok/core/AST.java index d568484e..31b8f0fd 100644 --- a/src/lombok/core/AST.java +++ b/src/lombok/core/AST.java @@ -39,26 +39,28 @@ 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 A Self-type. + * @param L type of all LombokNodes. * @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. + * For example, JCTree for javac, and ASTNode for Eclipse. */ -public abstract class AST<N> { +public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, 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; } - private Node top; + private L top; private final String fileName; - private Map<N, Void> identityDetector = new IdentityHashMap<N, Void>(); - private Map<N, Node> nodeMap = new IdentityHashMap<N, Node>(); + Map<N, Void> identityDetector = new IdentityHashMap<N, Void>(); + private Map<N, L> nodeMap = new IdentityHashMap<N, L>(); protected AST(String fileName) { this.fileName = fileName == null ? "(unknown).java" : fileName; } /** Set the node object that wraps the internal Compilation Unit node. */ - protected void setTop(Node top) { + protected void setTop(L top) { this.top = top; } @@ -80,14 +82,14 @@ public abstract class AST<N> { * 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) { + protected L putInMap(L 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() { + protected Map<N, L> getNodeMap() { return nodeMap; } @@ -95,7 +97,7 @@ public abstract class AST<N> { * object is left untouched, and instead a new map is created. */ protected void clearState() { identityDetector = new IdentityHashMap<N, Void>(); - nodeMap = new IdentityHashMap<N, Node>(); + nodeMap = new IdentityHashMap<N, L>(); } /** @@ -104,7 +106,7 @@ public abstract class AST<N> { * case you should do nothing lest the AST build process loops endlessly. */ protected boolean setAndGetAsHandled(N node) { - if ( identityDetector.containsKey(node) ) return true; + if (identityDetector.containsKey(node)) return true; identityDetector.put(node, null); return false; } @@ -114,23 +116,23 @@ public abstract class AST<N> { } /** The AST.Node object representing the Compilation Unit. */ - public Node top() { + public L top() { return top; } /** Maps a javac/Eclipse internal AST Node to the appropriate AST.Node object. */ - public Node get(N node) { + public L get(N node) { return nodeMap.get(node); } @SuppressWarnings("unchecked") - private Node replaceNewWithExistingOld(Map<N, Node> oldNodes, Node newNode) { - Node oldNode = oldNodes.get(newNode.get()); - Node targetNode = oldNode == null ? newNode : oldNode; + L replaceNewWithExistingOld(Map<N, L> oldNodes, L newNode) { + L oldNode = oldNodes.get(newNode.get()); + L targetNode = oldNode == null ? newNode : oldNode; List children = new ArrayList(); - for ( Node child : newNode.children ) { - Node oldChild = replaceNewWithExistingOld(oldNodes, child); + for (L child : newNode.children) { + L oldChild = replaceNewWithExistingOld(oldNodes, child); children.add(oldChild); oldChild.parent = targetNode; } @@ -140,262 +142,8 @@ 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; - this.children = children == null ? new ArrayList<Node>() : children; - for ( Node child : this.children ) child.parent = this; - 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 get method. - * - * @see AST#get(Object) - */ - 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); - newNode.parent = parent; - for ( int i = 0 ; i < parent.children.size() ; i++ ) { - if ( parent.children.get(i) == this ) ((List)parent.children).set(i, newNode); - } - - parent.replaceChildNode(get(), newN); - 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); - } - - public Kind getKind() { - return kind; - } - - /** - * Return the name of your type (simple name), method, field, or local variable. Return null if this - * node doesn't really have a name, such as initializers, while statements, etc. - */ - public abstract String getName(); - - /** Returns the structurally significant node that encloses this one. - * - * @see #isStructurallySignificant() - */ - public Node up() { - Node result = parent; - while ( result != null && !result.isStructurallySignificant ) result = result.parent; - return result; - } - - /** - * Returns the direct parent node in the AST tree of this node. For example, a local variable declaration's - * direct parent can be e.g. an If block, but its up() Node is the Method that contains it. - */ - public Node directUp() { - 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; - n.parent = this; - ((List)children).add(n); - return n; - } - - /** - * Reparses the AST node represented by this node. Any existing nodes that occupy a different space in the AST are rehomed, any - * nodes that no longer exist are removed, and new nodes are created. - * - * Careful - the node you call this on must not itself have been removed or rehomed - it rebuilds <i>all children</i>. - */ - public void rebuild() { - Map<N, Node> oldNodes = new IdentityHashMap<N, Node>(); - gatherAndRemoveChildren(oldNodes); - - Node newNode = buildTree(get(), kind); - - replaceNewWithExistingOld(oldNodes, newNode); - } - - private void gatherAndRemoveChildren(Map<N, Node> map) { - for ( Node child : children ) child.gatherAndRemoveChildren(map); - identityDetector.remove(get()); - map.put(get(), this); - children.clear(); - 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); - - /** - * Structurally significant means: LocalDeclaration, TypeDeclaration, MethodDeclaration, ConstructorDeclaration, - * FieldDeclaration, Initializer, and CompilationUnitDeclaration. - * The rest is e.g. if statements, while loops, etc. - */ - public boolean isStructurallySignificant() { - return isStructurallySignificant; - } - } - /** Build an AST.Node object for the stated internal (javac/Eclipse) AST Node object. */ - protected abstract Node buildTree(N item, Kind kind); + protected abstract L buildTree(N item, Kind kind); /** * Represents a field that contains AST children. @@ -420,7 +168,7 @@ public abstract class AST<N> { */ protected Collection<FieldAccess> fieldsOf(Class<?> c) { Collection<FieldAccess> fields = fieldsOfASTClasses.get(c); - if ( fields != null ) return fields; + if (fields != null) return fields; fields = new ArrayList<FieldAccess>(); getFields(c, fields); @@ -429,26 +177,26 @@ public abstract class AST<N> { } private void getFields(Class<?> c, Collection<FieldAccess> fields) { - if ( c == Object.class || c == null ) return; - for ( Field f : c.getDeclaredFields() ) { - if ( Modifier.isStatic(f.getModifiers()) ) continue; + if (c == Object.class || c == null) return; + for (Field f : c.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) continue; Class<?> t = f.getType(); int dim = 0; - if ( t.isArray() ) { - while ( t.isArray() ) { + if (t.isArray()) { + while (t.isArray()) { dim++; t = t.getComponentType(); } - } else if ( Collection.class.isAssignableFrom(t) ) { - while ( Collection.class.isAssignableFrom(t) ) { + } else { + while (Collection.class.isAssignableFrom(t)) { dim++; t = getComponentType(f.getGenericType()); } } - for ( Class<?> statementType : getStatementTypes() ) { - if ( statementType.isAssignableFrom(t) ) { + for (Class<?> statementType : getStatementTypes()) { + if (statementType.isAssignableFrom(t)) { f.setAccessible(true); fields.add(new FieldAccess(f, dim)); break; @@ -459,10 +207,12 @@ public abstract class AST<N> { } private Class<?> getComponentType(Type type) { - if ( type instanceof ParameterizedType ) { + if (type instanceof ParameterizedType) { Type component = ((ParameterizedType)type).getActualTypeArguments()[0]; return component instanceof Class<?> ? (Class<?>)component : Object.class; - } else return Object.class; + } else { + return Object.class; + } } /** @@ -473,8 +223,8 @@ public abstract class AST<N> { /** * 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>(); + protected Collection<L> buildWithField(Class<L> nodeType, N statement, FieldAccess fa) { + List<L> list = new ArrayList<L>(); buildWithField0(nodeType, statement, fa, list); return list; } @@ -483,8 +233,8 @@ public abstract class AST<N> { * 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; + for (FieldAccess fa : fieldsOf(statement.getClass())) { + if (replaceStatementInField(fa, statement, oldN, newN)) return true; } return false; @@ -493,42 +243,42 @@ public abstract class AST<N> { private boolean replaceStatementInField(FieldAccess fa, N statement, N oldN, N newN) { try { Object o = fa.field.get(statement); - if ( o == null ) return false; + if (o == null) return false; - if ( o == oldN ) { + if (o == oldN) { fa.field.set(statement, newN); return true; } - if ( fa.dim > 0 ) { - if ( o.getClass().isArray() ) { + if (fa.dim > 0) { + if (o.getClass().isArray()) { return replaceStatementInArray(o, oldN, newN); - } else if ( Collection.class.isInstance(o) ) { + } else if (Collection.class.isInstance(o)) { return replaceStatementInCollection(fa.field, statement, new ArrayList<Collection<?>>(), (Collection<?>)o, oldN, newN); } } return false; - } catch ( IllegalAccessException e ) { + } catch (IllegalAccessException e) { throw sneakyThrow(e); } } private boolean replaceStatementInCollection(Field field, Object fieldRef, List<Collection<?>> chain, Collection<?> collection, N oldN, N newN) throws IllegalAccessException { - if ( collection == null ) return false; + if (collection == null) return false; int idx = -1; - for ( Object o : collection ) { + for (Object o : collection) { idx++; - if ( o == null ) continue; - if ( Collection.class.isInstance(o) ) { + if (o == null) continue; + if (Collection.class.isInstance(o)) { Collection<?> newC = (Collection<?>)o; List<Collection<?>> newChain = new ArrayList<Collection<?>>(chain); newChain.add(newC); - if ( replaceStatementInCollection(field, fieldRef, newChain, newC, oldN, newN) ) return true; + if (replaceStatementInCollection(field, fieldRef, newChain, newC, oldN, newN)) return true; } - if ( o == oldN ) { + if (o == oldN) { setElementInASTCollection(field, fieldRef, chain, collection, idx, newN); return true; } @@ -540,21 +290,21 @@ public abstract class AST<N> { /** Override if your AST collection does not support the set method. Javac's for example, does not. */ @SuppressWarnings("unchecked") protected void setElementInASTCollection(Field field, Object fieldRef, List<Collection<?>> chain, Collection<?> collection, int idx, N newN) throws IllegalAccessException { - if ( collection instanceof List<?> ) { + if (collection instanceof List<?>) { ((List)collection).set(idx, newN); } } private boolean replaceStatementInArray(Object array, N oldN, N newN) { - if ( array == null ) return false; + if (array == null) return false; int len = Array.getLength(array); - for ( int i = 0 ; i < len ; i++ ) { + for (int i = 0; i < len; i++) { Object o = Array.get(array, i); - if ( o == null ) continue; - if ( o.getClass().isArray() ) { - if ( replaceStatementInArray(o, oldN, newN) ) return true; - } else if ( o == oldN ) { + if (o == null) continue; + if (o.getClass().isArray()) { + if (replaceStatementInArray(o, oldN, newN)) return true; + } else if (o == oldN) { Array.set(array, i, newN); return true; } @@ -564,39 +314,46 @@ public abstract class AST<N> { } @SuppressWarnings("unchecked") - private <T extends Node> void buildWithField0(Class<T> nodeType, N child, FieldAccess fa, Collection<T> list) { + private void buildWithField0(Class<L> nodeType, N child, FieldAccess fa, Collection<L> list) { try { Object o = fa.field.get(child); - if ( o == null ) return; - if ( fa.dim == 0 ) { - Node node = buildTree((N)o, Kind.STATEMENT); - if ( node != null ) list.add(nodeType.cast(node)); - } else if ( o.getClass().isArray() ) buildWithArray(nodeType, o, list, fa.dim); - else if ( Collection.class.isInstance(o) ) buildWithCollection(nodeType, o, list, fa.dim); - } catch ( IllegalAccessException e ) { + if (o == null) return; + if (fa.dim == 0) { + L node = buildTree((N)o, Kind.STATEMENT); + if (node != null) list.add(nodeType.cast(node)); + } else if (o.getClass().isArray()) { + buildWithArray(nodeType, o, list, fa.dim); + } else if (Collection.class.isInstance(o)) { + buildWithCollection(nodeType, o, list, fa.dim); + } + } catch (IllegalAccessException e) { sneakyThrow(e); } } @SuppressWarnings("unchecked") - private <T extends Node> void buildWithArray(Class<T> nodeType, Object array, Collection<T> list, int dim) { - if ( dim == 1 ) for ( Object v : (Object[])array ) { - if ( v == null ) continue; - Node node = buildTree((N)v, Kind.STATEMENT); - if ( node != null ) list.add(nodeType.cast(node)); - } else for ( Object v : (Object[])array ) { - if ( v == null ) return; - buildWithArray(nodeType, v, list, dim-1); + private void buildWithArray(Class<L> nodeType, Object array, Collection<L> list, int dim) { + if (dim == 1) { + for (Object v : (Object[])array) { + if (v == null) continue; + L node = buildTree((N)v, Kind.STATEMENT); + if (node != null) list.add(nodeType.cast(node)); + } + } else for (Object v : (Object[])array) { + if (v == null) return; + buildWithArray(nodeType, v, list, dim -1); } } @SuppressWarnings("unchecked") - private <T extends Node> void buildWithCollection(Class<T> nodeType, Object collection, Collection<T> list, int dim) { - if ( dim == 1 ) for ( Object v : (Collection<?>)collection ) { - if ( v == null ) continue; - Node node = buildTree((N)v, Kind.STATEMENT); - if ( node != null ) list.add(nodeType.cast(node)); - } else for ( Object v : (Collection<?>)collection ) { + private void buildWithCollection(Class<L> nodeType, Object collection, Collection<L> list, int dim) { + if (dim == 1) { + for (Object v : (Collection<?>)collection) { + if (v == null) continue; + L node = buildTree((N)v, Kind.STATEMENT); + if (node != null) list.add(nodeType.cast(node)); + } + } else for (Object v : (Collection<?>)collection) { buildWithCollection(nodeType, v, list, dim-1); } } diff --git a/src/lombok/core/AnnotationValues.java b/src/lombok/core/AnnotationValues.java index 663fb86b..fe16a395 100644 --- a/src/lombok/core/AnnotationValues.java +++ b/src/lombok/core/AnnotationValues.java @@ -37,7 +37,7 @@ import java.util.Map; public class AnnotationValues<A extends Annotation> { private final Class<A> type; private final Map<String, AnnotationValue> values; - private final AST<?>.Node ast; + private final LombokNode<?, ?, ?> ast; /** * Represents a single method on the annotation class. For example, the value() method on the Getter annotation. @@ -49,7 +49,7 @@ public class AnnotationValues<A extends Annotation> { /** Guesses for each raw expression. If the raw expression is a literal expression, the guess will * likely be right. If not, it'll be wrong. */ public final List<Object> valueGuesses; - private final AST<?>.Node node; + private final LombokNode<?, ?, ?> node; private final boolean isExplicit; /** @@ -59,7 +59,7 @@ public class AnnotationValues<A extends Annotation> { * For classes, supply the class name (qualified or not) as a string.<br /> * For enums, supply the simple name part (everything after the last dot) as a string.<br /> */ - public AnnotationValue(AST<?>.Node node, String raw, Object valueGuess, boolean isExplicit) { + public AnnotationValue(LombokNode<?, ?, ?> node, String raw, Object valueGuess, boolean isExplicit) { this.node = node; this.raws = Collections.singletonList(raw); this.valueGuesses = Collections.singletonList(valueGuess); @@ -69,7 +69,7 @@ public class AnnotationValues<A extends Annotation> { /** * Like the other constructor, but used for when the annotation method is |
