aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/lombok/core/AST.java15
-rw-r--r--src/core/lombok/core/AnnotationValues.java19
-rw-r--r--src/core/lombok/core/ImportList.java43
-rw-r--r--src/core/lombok/core/LombokNode.java58
-rw-r--r--src/core/lombok/core/TypeLibrary.java68
-rw-r--r--src/core/lombok/core/TypeResolver.java102
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java23
-rw-r--r--src/core/lombok/eclipse/EclipseImportList.java131
-rw-r--r--src/core/lombok/eclipse/HandlerLibrary.java41
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java2
-rw-r--r--src/core/lombok/javac/HandlerLibrary.java32
-rw-r--r--src/core/lombok/javac/JavacAST.java17
-rw-r--r--src/core/lombok/javac/JavacImportList.java105
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java2
-rw-r--r--src/utils/lombok/core/ImmutableList.java188
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java6
16 files changed, 599 insertions, 253 deletions
diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java
index 68f36412..644d9449 100644
--- a/src/core/lombok/core/AST.java
+++ b/src/core/lombok/core/AST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,7 +30,6 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
@@ -54,15 +53,15 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,
private L top;
private final String fileName;
private final String packageDeclaration;
- private final Collection<String> imports;
+ private final ImportList imports;
Map<N, Void> identityDetector = new IdentityHashMap<N, Void>();
private Map<N, L> nodeMap = new IdentityHashMap<N, L>();
private boolean changed = false;
- protected AST(String fileName, String packageDeclaration, Collection<String> imports) {
+ protected AST(String fileName, String packageDeclaration, ImportList imports) {
this.fileName = fileName == null ? "(unknown).java" : fileName;
this.packageDeclaration = packageDeclaration;
- this.imports = Collections.unmodifiableCollection(new ArrayList<String>(imports));
+ this.imports = imports;
}
public void setChanged() {
@@ -96,7 +95,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,
*
* Example: "java.util.IOException".
*/
- public final Collection<String> getImportStatements() {
+ public final ImportList getImportList() {
return imports;
}
@@ -159,8 +158,8 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,
oldChild.parent = targetNode;
}
- targetNode.children.clear();
- ((List)targetNode.children).addAll(children);
+ targetNode.children = ImmutableList.copyOf(children);
+
return targetNode;
}
diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java
index df056dd4..d04797cb 100644
--- a/src/core/lombok/core/AnnotationValues.java
+++ b/src/core/lombok/core/AnnotationValues.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -435,23 +435,16 @@ public class AnnotationValues<A extends Annotation> {
}
/* 2. Walk through non-star imports and search for a match. */ {
- for (String im : ast == null ? Collections.<String>emptyList() : ast.getImportStatements()) {
- if (im.endsWith(".*")) continue;
- int idx = im.lastIndexOf('.');
- String simple = idx == -1 ? im : im.substring(idx+1);
- if (simple.equals(prefix)) {
- return im + typeName.substring(prefix.length());
- }
+ if (prefix.equals(typeName)) {
+ String fqn = ast.getImportList().getFullyQualifiedNameForSimpleName(typeName);
+ if (fqn != null) return fqn;
}
}
/* 3. Walk through star imports and, if they start with "java.", use Class.forName based resolution. */ {
- List<String> imports = ast == null ? Collections.<String>emptyList() : new ArrayList<String>(ast.getImportStatements());
- imports.add("java.lang.*");
- for (String im : imports) {
- if (!im.endsWith(".*") || !im.startsWith("java.")) continue;
+ for (String potential : ast.getImportList().applyNameToStarImports("java", typeName)) {
try {
- Class<?> c = Class.forName(im.substring(0, im.length()-1) + typeName);
+ Class<?> c = Class.forName(potential);
if (c != null) return c.getName();
} catch (Throwable t) {
//Class.forName failed for whatever reason - it most likely does not exist, continue.
diff --git a/src/core/lombok/core/ImportList.java b/src/core/lombok/core/ImportList.java
new file mode 100644
index 00000000..95e266c4
--- /dev/null
+++ b/src/core/lombok/core/ImportList.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core;
+
+import java.util.Collection;
+
+public interface ImportList {
+ /**
+ * If there is an explicit import of the stated unqualified type name, return that. Otherwise, return null.
+ */
+ String getFullyQualifiedNameForSimpleName(String unqualified);
+
+ /**
+ * Returns true if the package name is explicitly star-imported, OR the packageName refers to this source file's own package name, OR packageName is 'java.lang'.
+ */
+ boolean hasStarImport(String packageName);
+
+ /**
+ * Takes all explicit non-static star imports whose first element is equal to {@code startsWith}, replaces the star with {@code unqualified}, and returns these.
+ */
+ Collection<String> applyNameToStarImports(String startsWith, String unqualified);
+
+ String applyUnqualifiedNameToPackage(String unqualified);
+}
diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java
index eac59806..588adc55 100644
--- a/src/core/lombok/core/LombokNode.java
+++ b/src/core/lombok/core/LombokNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2011 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -42,7 +42,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
protected final A ast;
protected final Kind kind;
protected final N node;
- protected final List<L> children;
+ protected ImmutableList<L> children;
protected L parent;
/** structurally significant are those nodes that can be annotated in java 1.6 or are method-like toplevels,
@@ -62,7 +62,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
this.ast = ast;
this.kind = kind;
this.node = node;
- this.children = children == null ? new ArrayList<L>() : children;
+ this.children = children != null ? ImmutableList.copyOf(children) : ImmutableList.<L>of();
for (L child : this.children) {
child.parent = (L) this;
if (!child.isStructurallySignificant)
@@ -91,12 +91,12 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
}
/**
- * Convenient shortcut to the owning ast object's {@code getImportStatements} method.
+ * Convenient shortcut to the owning ast object's {@code getImportList} method.
*
- * @see AST#getImportStatements()
+ * @see AST#getImportList()
*/
- public Collection<String> getImportStatements() {
- return ast.getImportStatements();
+ public ImportList getImportList() {
+ return ast.getImportList();
}
/**
@@ -120,35 +120,6 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
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({"rawtypes", "unchecked"})
- public L replaceWith(N newN, Kind newNodeKind) {
- ast.setChanged();
- L newNode = ast.buildTree(newN, newNodeKind);
- 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) {
- ast.setChanged();
- ast.replaceStatementInNode(get(), oldN, newN);
- }
-
public Kind getKind() {
return kind;
}
@@ -204,12 +175,9 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
/**
* 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 {@code ConcurrentModificationException}s.
*/
- public Collection<L> down() {
- return new ArrayList<L>(children);
+ public ImmutableList<L> down() {
+ return children;
}
/**
@@ -235,13 +203,13 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
*
* Does not change the underlying (javac/Eclipse) AST, only the wrapped view.
*/
- @SuppressWarnings({"rawtypes", "unchecked"})
+ @SuppressWarnings({"unchecked"})
public L add(N newChild, Kind newChildKind) {
ast.setChanged();
L n = ast.buildTree(newChild, newChildKind);
if (n == null) return null;
n.parent = (L) this;
- ((List)children).add(n);
+ children = children.append(n);
return n;
}
@@ -267,7 +235,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
for (LombokNode child : children) child.gatherAndRemoveChildren(map);
ast.identityDetector.remove(get());
map.put(get(), (L) this);
- children.clear();
+ children = ImmutableList.of();
ast.getNodeMap().remove(get());
}
@@ -278,7 +246,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
*/
public void removeChild(L child) {
ast.setChanged();
- children.remove(child);
+ children = children.removeElement(child);
}
/**
diff --git a/src/core/lombok/core/TypeLibrary.java b/src/core/lombok/core/TypeLibrary.java
index 0e3f7bf4..a89091c4 100644
--- a/src/core/lombok/core/TypeLibrary.java
+++ b/src/core/lombok/core/TypeLibrary.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,12 +21,7 @@
*/
package lombok.core;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -40,24 +35,23 @@ import java.util.Map;
* <ul><li>foo.Spork</li><li>Spork</li><li>foo.*</li></ul>
*/
public class TypeLibrary {
- private final Map<String, List<String>> keyToFqnMap;
- private final String singletonValue;
- private final List<String> singletonKeys;
+ private final Map<String, String> unqualifiedToQualifiedMap;
+ private final String unqualified, qualified;
public TypeLibrary() {
- keyToFqnMap = new HashMap<String, List<String>>();
- singletonKeys = null;
- singletonValue = null;
+ unqualifiedToQualifiedMap = new HashMap<String, String>();
+ unqualified = null;
+ qualified = null;
}
private TypeLibrary(String fqnSingleton) {
- keyToFqnMap = null;
- singletonValue = fqnSingleton;
+ unqualifiedToQualifiedMap = null;
+ qualified = fqnSingleton;
int idx = fqnSingleton.lastIndexOf('.');
if (idx == -1) {
- singletonKeys = Collections.singletonList(fqnSingleton);
+ unqualified = fqnSingleton;
} else {
- singletonKeys = Arrays.asList(fqnSingleton, fqnSingleton.substring(idx + 1), fqnSingleton.substring(0, idx) + ".*");
+ unqualified = fqnSingleton.substring(idx + 1);
}
}
@@ -71,42 +65,28 @@ public class TypeLibrary {
* @param fullyQualifiedTypeName the FQN type name, such as 'java.lang.String'.
*/
public void addType(String fullyQualifiedTypeName) {
- if (keyToFqnMap == null) throw new IllegalStateException("SingleType library");
+ fullyQualifiedTypeName = fullyQualifiedTypeName.replace("$", ".");
int idx = fullyQualifiedTypeName.lastIndexOf('.');
if (idx == -1) throw new IllegalArgumentException(
"Only fully qualified types are allowed (and stuff in the default package is not palatable to us either!)");
+ String unqualified = fullyQualifiedTypeName.substring(idx + 1);
+ if (unqualifiedToQualifiedMap == null) throw new IllegalStateException("SingleType library");
- fullyQualifiedTypeName = fullyQualifiedTypeName.replace("$", ".");
- final String simpleName = fullyQualifiedTypeName.substring(idx +1);
- final String packageName = fullyQualifiedTypeName.substring(0, idx);
-
- if (keyToFqnMap.put(fullyQualifiedTypeName, Collections.singletonList(fullyQualifiedTypeName)) != null) return;
-
- addToMap(simpleName, fullyQualifiedTypeName);
- addToMap(packageName + ".*", fullyQualifiedTypeName);
- }
-
- private TypeLibrary addToMap(String keyName, String fullyQualifiedTypeName) {
- List<String> list = keyToFqnMap.get(keyName);
- if (list == null) {
- list = new ArrayList<String>();
- keyToFqnMap.put(keyName, list);
- }
-
- list.add(fullyQualifiedTypeName);
- return this;
+ unqualifiedToQualifiedMap.put(unqualified, fullyQualifiedTypeName);
+ unqualifiedToQualifiedMap.put(fullyQualifiedTypeName, fullyQualifiedTypeName);
}
/**
- * Returns all items in the type library that may be a match to the provided type.
+ * Translates an unqualified name such as 'String' to 'java.lang.String', _if_ you added 'java.lang.String' to the library via the {@code addType} method.
+ * Also returns the input if it is equal to a fully qualified name added to this type library.
*
- * @param typeReference something like 'String', 'java.lang.String', or 'java.lang.*'.
- * @return A list of Fully Qualified Names for all types in the library that fit the reference.
+ * Returns null if it does not match any type in this type library.
*/
- public Collection<String> findCompatible(String typeReference) {
- if (singletonKeys != null) return singletonKeys.contains(typeReference) ? Collections.singletonList(singletonValue) : Collections.<String>emptyList();
-
- List<String> result = keyToFqnMap.get(typeReference);
- return result == null ? Collections.<String>emptyList() : Collections.unmodifiableList(result);
+ public String toQualified(String typeReference) {
+ if (unqualifiedToQualifiedMap == null) {
+ if (typeReference.equals(unqualified) || typeReference.equals(qualified)) return qualified;
+ return null;
+ }
+ return unqualifiedToQualifiedMap.get(typeReference);
}
}
diff --git a/src/core/lombok/core/TypeResolver.java b/src/core/lombok/core/TypeResolver.java
index 27f0bfc1..e2ba03b5 100644
--- a/src/core/lombok/core/TypeResolver.java
+++ b/src/core/lombok/core/TypeResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2011 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,11 +21,6 @@
*/
package lombok.core;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
import lombok.core.AST.Kind;
/**
@@ -35,60 +30,54 @@ import lombok.core.AST.Kind;
* and this importer also can't find inner types from superclasses/interfaces.
*/
public class TypeResolver {
- private Collection<String> imports;
+ private ImportList imports;
/**
* Creates a new TypeResolver that can be used to resolve types in a source file with the given package and import statements.
*/
- public TypeResolver(String packageString, Collection<String> importStrings) {
- this.imports = makeImportList(packageString, importStrings);
- }
-
- private static Collection<String> makeImportList(String packageString, Collection<String> importStrings) {
- Set<String> imports = new HashSet<String>();
- if (packageString != null) imports.add(packageString + ".*");
- imports.addAll(importStrings == null ? Collections.<String>emptySet() : importStrings);
- imports.add("java.lang.*");
- return imports;
+ public TypeResolver(ImportList importList) {
+ this.imports = importList;
}
+// private static ImportList makeImportList(String packageString, Collection<String> importStrings) {
+// Set<String> imports = new HashSet<String>();
+// if (packageString != null) imports.add(packageString + ".*");
+// imports.addAll(importStrings == null ? Collections.<String>emptySet() : importStrings);
+// imports.add("java.lang.*");
+// return imports;
+// }
+//
public boolean typeMatches(LombokNode<?, ?, ?> context, String fqn, String typeRef) {
- return !findTypeMatches(context, TypeLibrary.createLibraryForSingleType(fqn), typeRef).isEmpty();
+ return typeRefToFullyQualifiedName(context, TypeLibrary.createLibraryForSingleType(fqn), typeRef) != null;
}
- /**
- * 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(LombokNode<?, ?, ?> context, TypeLibrary library, String typeRef) {
+ public String typeRefToFullyQualifiedName(LombokNode<?, ?, ?> context, TypeLibrary library, String typeRef) {
// When asking if 'Foo' could possibly be referring to 'bar.Baz', the answer is obviously no.
- Collection<String> potentialMatches = library.findCompatible(typeRef);
- if (potentialMatches.isEmpty()) return Collections.emptyList();
+ String qualified = library.toQualified(typeRef);
+ if (qualified == null) return null;
- // If input type appears to be fully qualified, we found a winner.
- int idx = typeRef.indexOf('.');
- if (idx > -1) return potentialMatches;
+ // When asking if 'lombok.Getter' could possibly be referring to 'lombok.Getter', the answer is obviously yes.
+ if (typeRef.equals(qualified)) return typeRef;
- // If there's an import statement that explicitly imports a 'Getter' that isn't any of our potentials, return no matches,
- // because if you want to know if 'Foo' could refer to 'bar.Foo' when 'baz.Foo' is explicitly imported, the answer is no.
- if (nameConflictInImportList(typeRef, potentialMatches)) return Collections.emptyList();
+ // When asking if 'Getter' could possibly be referring to 'lombok.Getter' if 'import lombok.Getter;' is in the source file, the answer is yes.
+ String fromExplicitImport = imports.getFullyQualifiedNameForSimpleName(typeRef);
+ if (fromExplicitImport != null) {
+ // ... and if 'import foobar.Getter;' is in the source file, the answer is no.
+ return fromExplicitImport.equals(qualified) ? qualified : null;
+ }
- // Check if any of our potentials are even imported in the first place. If not: no matches.
- // Note that (ourPackage.*) is added to the imports.
- potentialMatches = eliminateImpossibleMatches(potentialMatches, library);
- if (potentialMatches.isEmpty()) return Collections.emptyList();
+ // When asking if 'Getter' could possibly be referring to 'lombok.Getter' and 'import lombok.*; / package lombok;' isn't in the source file. the answer is no.
+ String pkgName = qualified.substring(0, qualified.length() - typeRef.length() - 1);
+ if (!imports.hasStarImport(pkgName)) return null;
- // Now the hard part - inner classes or method local classes in our own scope.
- // For method locals, this refers to any statements that are 'above' the type reference with the same name.
- // For inners, this refers to siblings of us or any parent node that are type declarations.
+ // Now the hard part: Given that there is a star import, 'Getter' most likely refers to 'lombok.Getter', but type shadowing may occur in which case it doesn't.
LombokNode<?, ?, ?> n = context;
mainLoop:
while (n != null) {
if (n.getKind() == Kind.TYPE && typeRef.equals(n.getName())) {
// Our own class or one of our outer classes is named 'typeRef' so that's what 'typeRef' is referring to, not one of our type library classes.
- return Collections.emptyList();
+ return null;
}
if (n.getKind() == Kind.STATEMENT || n.getKind() == Kind.LOCAL) {
@@ -99,7 +88,7 @@ public class TypeResolver {
for (LombokNode<?, ?, ?> child : newN.down()) {
// We found a method local with the same name above our code. That's the one 'typeRef' is referring to, not
// anything in the type library we're trying to find, so, no matches.
- if (child.getKind() == Kind.TYPE && typeRef.equals(child.getName())) return Collections.emptyList();
+ if (child.getKind() == Kind.TYPE && typeRef.equals(child.getName())) return null;
if (child == n) break;
}
}
@@ -110,41 +99,14 @@ public class TypeResolver {
if (n.getKind() == Kind.TYPE || n.getKind() == Kind.COMPILATION_UNIT) {
for (LombokNode<?, ?, ?> child : n.down()) {
// Inner class that's visible to us has 'typeRef' as name, so that's the one being referred to, not one of our type library classes.
- if (child.getKind() == Kind.TYPE && typeRef.equals(child.getName())) return Collections.emptyList();
+ if (child.getKind() == Kind.TYPE && typeRef.equals(child.getName())) return null;
}
}
n = n.directUp();
}
- // No class in this source file is a match, therefore the potential matches found via the import statements must be it. Return those.
- return potentialMatches;
- }
-
- private Collection<String> eliminateImpossibleMatches(Collection<String> potentialMatches, TypeLibrary library) {
- Set<String> results = new HashSet<String>();
-
- for (String importedType : imports) {
- Collection<String> reduced = new HashSet<String>(library.findCompatible(importedType));
- reduced.retainAll(potentialMatches);
- results.addAll(reduced);
- }
-
- return results;
- }
-
- private boolean nameConflictInImportList(String simpleName, Collection<String> potentialMatches) {
- for (String importedType : imports) {
- if (!toSimpleName(importedType).equals(simpleName)) continue;
- if (potentialMatches.contains(importedType)) continue;
- return true;
- }
- return false;
- }
-
- private static String toSimpleName(String typeName) {
- int idx = typeName.lastIndexOf('.');
- return idx == -1 ? typeName : typeName.substring(idx+1);
+ return qualified;
}
}
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java
index 8ab42140..d1f4ff06 100644
--- a/src/core/lombok/eclipse/EclipseAST.java
+++ b/src/core/lombok/eclipse/EclipseAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,6 +30,7 @@ import java.util.List;
import lombok.Lombok;
import lombok.core.AST;
+import lombok.core.ImmutableList;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -55,7 +56,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
* @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), packageDeclaration(ast), imports(ast));
+ super(toFileName(ast), packageDeclaration(ast), new EclipseImportList(ast));
this.compilationUnitDeclaration = ast;
setTop(buildCompilationUnit(ast));
this.completeParse = isComplete(ast);
@@ -67,18 +68,6 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
return pkg == null ? null : Eclipse.toQualifiedName(pkg.getImportName());
}
- private static Collection<String> imports(CompilationUnitDeclaration cud) {
- List<String> imports = new ArrayList<String>();
- if (cud.imports == null) return imports;
- for (ImportReference imp : cud.imports) {
- if (imp == null) continue;
- String qualifiedName = Eclipse.toQualifiedName(imp.getImportName());
- if ((imp.bits & ASTNode.OnDemand) != 0) qualifiedName += ".*";
- imports.add(qualifiedName);
- }
- return imports;
- }
-
/**
* Runs through the entire AST, starting at the compilation unit, calling the provided visitor's visit methods
* for each node, depth first.
@@ -88,8 +77,10 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
}
void traverseChildren(EclipseASTVisitor visitor, EclipseNode node) {
- for (EclipseNode child : node.down()) {
- child.traverse(visitor);
+ ImmutableList<EclipseNode> children = node.down();
+ int len = children.size();
+ for (int i = 0; i < len; i++) {
+ children.get(i).traverse(visitor);
}
}
diff --git a/src/core/lombok/eclipse/EclipseImportList.java b/src/core/lombok/eclipse/EclipseImportList.java
new file mode 100644
index 00000000..264ed91f
--- /dev/null
+++ b/src/core/lombok/eclipse/EclipseImportList.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.eclipse;
+
+import static lombok.eclipse.Eclipse.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+
+import lombok.core.ImportList;
+
+public class EclipseImportList implements ImportList {
+ private ImportReference[] imports;
+ private ImportReference pkg;
+
+ public EclipseImportList(CompilationUnitDeclaration cud) {
+ this.pkg = cud.currentPackage;
+ this.imports = cud.imports;
+ }
+
+ @Override public String getFullyQualifiedNameForSimpleName(String unqualified) {
+ if (imports != null) {
+ outer:
+ for (ImportReference imp : imports) {
+ if ((imp.bits & ASTNode.OnDemand) != 0) continue;
+ char[][] tokens = imp.tokens;
+ char[] token = tokens.length == 0 ? new char[0] : tokens[tokens.length - 1];
+ int len = token.length;
+ if (len != unqualified.length()) continue;
+ for (int i = 0; i < len; i++) if (token[i] != unqualified.charAt(i)) continue outer;
+ return toQualifiedName(tokens);
+ }
+ }
+ return null;
+ }
+
+ @Override public boolean hasStarImport(String packageName) {
+ if (isEqual(packageName, pkg)) return true;
+ if ("java.lang".equals(packageName)) return true;
+ if (imports != null) for (ImportReference imp : imports) {
+ if ((imp.bits & ASTNode.OnDemand) == 0) continue;
+ if (imp.isStatic()) continue;
+ if (isEqual(packageName, imp)) return true;
+ }
+ return false;
+ }
+
+ private static boolean isEqual(String packageName, ImportReference pkgOrStarImport) {
+ if (pkgOrStarImport == null || pkgOrStarImport.tokens == null || pkgOrStarImport.tokens.length == 0) return packageName.isEmpty();
+ int pos = 0;
+ int len = packageName.length();
+ for (int i = 0; i < pkgOrStarImport.tokens.length; i++) {
+ if (i != 0) {
+ if (pos >= len) return false;
+ if (packageName.charAt(pos++) != '.') return false;
+ }
+ for (int j = 0; j < pkgOrStarImport.tokens[i].length; j++) {
+ if (pos >= len) return false;
+ if (packageName.charAt(pos++) != pkgOrStarImport.tokens[i][j]) return false;
+ }
+ }
+ return true;
+ }
+
+ @Override public Collection<String> applyNameToStarImports(String startsWith, String name) {
+ List<String> out = Collections.emptyList();
+
+ if (pkg != null && pkg.tokens != null && pkg.tokens.length != 0) {
+ char[] first = pkg.tokens[0];
+ int len = first.length;
+ boolean match = true;
+ if (startsWith.length() == len) {
+ for (int i = 0; match && i < len; i++) {
+ if (startsWith.charAt(i) != first[i]) match = false;
+ }
+ if (match) out.add(toQualifiedName(pkg.tokens) + "." + name);
+ }
+ }
+
+ if (imports != null) {
+ outer:
+ for (ImportReference imp : imports) {
+ if ((imp.bits & ASTNode.OnDemand) == 0) continue;
+ if (imp.isStatic()) continue;
+ if (imp.tokens == null || imp.tokens.length == 0) continue;
+ char[] firstToken = imp.tokens[0];
+ if (firstToken.length != startsWith.length()) continue;
+ for (int i = 0; i < firstToken.length; i++) if (startsWith.charAt(i) != firstToken[i]) continue outer;
+ String fqn = toQualifiedName(imp.tokens) + "." + name;
+ if (out.isEmpty()) out = Collections.singletonList(fqn);
+ else if (out.size() == 1) {
+ out = new ArrayList<String>(out);
+ out.add(fqn);
+ } else {
+ out.add(fqn);
+ }
+ }
+ }
+ return out;
+ }
+
+ @Override public String applyUnqualifiedNameToPackage(String unqualified) {
+ if (pkg == null || pkg.tokens == null || pkg.tokens.length == 0) return unqualified;
+ return toQualifiedName(pkg.tokens) + "." + unqualified;
+ }
+}
diff --git a/src/core/lombok/eclipse/HandlerLibrary.java b/src/core/lombok/eclipse/HandlerLibrary.java
index 56744793..242e923c 100644
--- a/src/core/lombok/eclipse/HandlerLibrary.java
+++ b/src/core/lombok/eclipse/HandlerLibrary.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -218,30 +218,27 @@ public class HandlerLibrary {
* @param annotation 'node.get()' - convenience parameter.
*/
public void handleAnnotation(CompilationUnitDeclaration ast, EclipseNode annotationNode, org.eclipse.jdt.internal.compiler.ast.Annotation annotation, long priority) {
- String pkgName = annotationNode.getPackageDeclaration();
- Collection<String> imports = annotationNode.getImportStatements();
-
- TypeResolver resolver = new TypeResolver(pkgName, imports);
+ TypeResolver resolver = new TypeResolver(annotationNode.getImportList());
TypeReference rawType = annotation.type;
if (rawType == null) return;
- for (String fqn : resolver.findTypeMatches(annotationNode, typeLibrary, toQualifiedName(annotation.type.getTypeName()))) {
- AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
- if (container == null) continue;
- if (priority != container.getPriority()) continue;
-
- if (!annotationNode.isCompleteParse() && container.deferUntilPostDiet()) {
- if (needsHandling(annotation)) container.preHandle(annotation, annotationNode);
- continue;
- }
-
- try {
- if (checkAndSetHandled(annotation)) container.handle(annotation, annotationNode);
- } catch (AnnotationValueDecodeFail fail) {
- fail.owner.setError(fail.getMessage(), fail.idx);
- } catch (Throwable t) {
- error(ast, String.format("Lombok annotation handler %s failed", container.handler.getClass()), t);
- }
+ String fqn = resolver.typeRefToFullyQualifiedName(annotationNode, typeLibrary, toQualifiedName(annotation.type.getTypeName()));
+ if (fqn == null) return;
+ AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
+ if (container == null) return;
+ if (priority != container.getPriority()) return;
+
+ if (!annotationNode.isCompleteParse() && container.deferUntilPostDiet()) {
+ if (needsHandling(annotation)) container.preHandle(annotation, annotationNode);
+ return;
+ }
+
+ try {
+ if (checkAndSetHandled(annotation)) container.handle(annotation, annotationNode);
+ } catch (AnnotationValueDecodeFail fail) {
+ fail.owner.setError(fail.getMessage(), fail.idx);
+ } catch (Throwable t) {
+ error(ast, String.format("Lombok annotation handler %s failed", container.handler.getClass()), t);
}
}
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 78780522..d47b6715 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -290,7 +290,7 @@ public class EclipseHandlerUtil {
if (!lastPartA.equals(lastPartB)) return false;
String typeName = toQualifiedName(typeRef.getTypeName());
- TypeResolver resolver = new TypeResolver(node.getPackageDeclaration(), node.getImportStatements());
+ TypeResolver resolver = new TypeResolver(node.getImportList());
return resolver.typeMatches(node, type.getName(), typeName);
}
diff --git a/src/core/lombok/javac/HandlerLibrary.java b/src/core/lombok/javac/HandlerLibrary.java
index 2be84355..4306b5f2 100644
--- a/src/core/lombok/javac/HandlerLibrary.java
+++ b/src/core/lombok/javac/HandlerLibrary.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -231,23 +231,23 @@ public class HandlerLibrary {
* @param annotation 'node.get()' - convenience parameter.
*/
public void handleAnnotation(JCCompilationUnit unit, JavacNode node, JCAnnotation annotation, long priority) {
- TypeResolver resolver = new TypeResolver(node.getPackageDeclaration(), node.getImportStatements());
+ TypeResolver resolver = new TypeResolver(node.getImportList());
String rawType = annotation.annotationType.toString();
- for (String fqn : resolver.findTypeMatches(node, typeLibrary, rawType)) {
- AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
- if (container == null) continue;
-
- try {
- if (container.getPriority() == priority) {
- if (checkAndSetHandled(annotation)) container.handle(node);
- }
- } catch (AnnotationValueDecodeFail fail) {
- fail.owner.setError(fail.getMessage(), fail.idx);
- } catch (Throwable t) {
- String sourceName = "(unknown).java";
- if (unit != null && unit.sourcefile != null) sourceName = unit.sourcefile.getName();
- javacError(String.format("Lombok annotation handler %s failed on " + sourceName, container.handler.getClass()), t);
+ String fqn = resolver.typeRefToFullyQualifiedName(node, typeLibrary, rawType);
+ if (fqn == null) return;
+ AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
+ if (container == null) return;
+
+ try {
+ if (container.getPriority() == priority) {
+ if (checkAndSetHandled(annotation)) container.handle(node);
}
+ } catch (AnnotationValueDecodeFail fail) {
+ fail.owner.setError(fail.getMessage(), fail.idx);
+ } catch (Throwable t) {
+ String sourceName = "(unknown).java";
+ if (unit != null && unit.sourcefile != null) sourceName = unit.sourcefile.getName();
+ javacError(String.format("Lombok annotation handler %s failed on " + sourceName, container.handler.getClass()), t);
}
}
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index 71c17538..93ea9754 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -46,7 +46,6 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
-import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
@@ -78,7 +77,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
* @param top The compilation unit, which serves as the top level node in the tree to be built.
*/
public JavacAST(Messager messager, Context context, JCCompilationUnit top) {
- super(sourceName(top), packageDeclaration(top), imports(top));
+ super(sourceName(top), packageDeclaration(top), new JavacImportList(top));
setTop(buildCompilationUnit(top));
this.context = context;
this.messager = messager;
@@ -98,16 +97,6 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
return (cu.pid instanceof JCFieldAccess || cu.pid instanceof JCIdent) ? cu.pid.toString() : null;
}
- private static Collection<String> imports(JCCompilationUnit cu) {
- List<String> imports = new ArrayList<String>();
- for (JCTree def : cu.defs) {
- if (def instanceof JCImport) {
- imports.add(((JCImport)def).qualid.toString());
- }
- }
- return imports;
- }
-
public Context getContext() {
return context;
}
@@ -121,9 +110,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
}
void traverseChildren(JavacASTVisitor visitor, JavacNode node) {
- for (JavacNode child : new ArrayList<JavacNode>(node.down())) {
- child.traverse(visitor);
- }
+ for (JavacNode child : node.down()) child.traverse(visitor);
}
/** @return A Name object generated for the proper name table belonging to this AST. */
diff --git a/src/core/lombok/javac/JavacImportList.java b/src/core/lombok/javac/JavacImportList.java
new file mode 100644
index 00000000..fbd4a518
--- /dev/null
+++ b/src/core/lombok/javac/JavacImportList.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.javac;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCImport;
+import com.sun.tools.javac.util.List;
+
+import lombok.core.ImportList;
+
+public class JavacImportList implements ImportList {
+ private final JCExpression pkg;
+ private final List<JCTree> defs;
+
+ public JavacImportList(JCCompilationUnit cud) {
+ this.pkg = cud.pid;
+ this.defs = cud.defs;
+ }
+
+ @Override public String getFullyQualifiedNameForSimpleName(String unqualified) {
+ for (JCTree def : defs) {
+ if (!(def instanceof JCImport)) continue;
+ JCTree qual = ((JCImport) def).qualid;
+ if (!(qual instanceof JCFieldAccess)) continue;
+ String simpleName = ((JCFieldAccess) qual).name.toString();
+ if (simpleName.equals(unqualified)) return qual.toString();
+ }
+
+ return null;
+ }
+
+ @Override public boolean hasStarImport(String packageName) {
+ if (pkg != null && pkg.toString().equals(packageName)) return true;
+ if ("java.lang".equals(packageName)) return true;
+
+ for (JCTree def : defs) {
+ if (!(def instanceof JCImport)) continue;
+ if (((JCImport) def).staticImport) continue;
+ JCTree qual = ((JCImport) def).qualid;
+ if (!(qual instanceof JCFieldAccess)) continue;
+ String simpleName = ((JCFieldAccess) qual).name.toString();
+ if (!"*".equals(simpleName)) continue;
+ if (packageName.equals(((JCFieldAccess) qual).selected.toString())) return true;
+ }
+
+ return false;
+ }
+
+ @Override public Collection<String> applyNameToStarImports(String startsWith, String name) {
+ ArrayList<String> out = new ArrayList<String>();
+
+ if (pkg != null && topLevelName(pkg).equals(startsWith)) out.add(pkg.toString() + "." + name);
+
+ for (JCTree def : defs) {
+ if (!(def instanceof JCImport)) continue;
+ if (((JCImport) def).staticImport) continue;
+ JCTree qual = ((JCImport) def).qualid;
+ if (!(qual instanceof JCFieldAccess)) continue;
+ String simpleName = ((JCFieldAccess) qual).name.toString();
+ if (!"*".equals(simpleName)) continue;
+
+ String topLevelName = topLevelName(qual);
+ if (topLevelName.equals(startsWith)) {
+ out.add(((JCFieldAccess) qual).selected.toString() + "." + name);
+ }
+ }
+
+ return out;
+ }
+
+ private String topLevelName(JCTree tree) {
+ while (tree instanceof JCFieldAccess) tree = ((JCFieldAccess) tree).selected;
+ return tree.toString();
+ }
+
+ @Override public String applyUnqualifiedNameToPackage(String unqualified) {
+ if (pkg == null) return unqualified;
+ return pkg.toString() + "." + unqualified;
+ }
+}
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index e79dd5dc..ef1a9f50 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -185,7 +185,7 @@ public class JavacHandlerUtil {
public static boolean typeMatches(Class<?> type, JavacNode node, JCTree typeNode) {
String typeName = typeNode.toString();
- TypeResolver resolver = new TypeResolver(node.getPackageDeclaration(), node.getImportStatements());
+ TypeResolver resolver = new TypeResolver(node.getImportList());
return resolver.typeMatches(node, type.getName(), typeName);
}
diff --git a/src/utils/lombok/core/ImmutableList.java b/src/utils/lombok/core/ImmutableList.java
new file mode 100644
index 00000000..a151ae6f
--- /dev/null
+++ b/src/utils/lombok/core/ImmutableList.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+public final class ImmutableList<T> implements Iterable<T> {
+ private Object[] content;
+ private static final ImmutableList<?> EMPTY = new ImmutableList<Object>(new Object[0]);
+
+ @SuppressWarnings("unchecked")
+ public static <T> ImmutableList<T> of() {
+ return (ImmutableList<T>) EMPTY;
+ }
+
+ public static <T> ImmutableList<T> of(T a) {
+ return new ImmutableList<T>(new Object[] {a});
+ }
+
+ public static <T> ImmutableList<T> of(T a, T b) {
+ return new ImmutableList<T>(new Object[] {a, b});
+ }
+
+ public static <T> ImmutableList<T> of(T a, T b, T c) {
+ return new ImmutableList<T>(new Object[] {a, b, c});
+ }
+
+ public static <T> ImmutableList<T> of(T a, T b, T c, T d) {
+ return new ImmutableList<T>(new Object[] {a, b, c, d});
+ }
+
+ public static <T> ImmutableList<T> of(T a, T b, T c, T d, T e) {
+ return new ImmutableList<T>(new Object[] {a, b, c, d, e});
+ }
+
+ public static <T> ImmutableList<T> of(T a, T b, T c, T d, T e, T f, @SuppressWarnings("unchecked") T... g) {
+ Object[] rest = g == null ? new Object[] {null} : g;
+ Object[] val = new Object[rest.length + 6];
+ System.arraycopy(rest, 0, val, 6, rest.length);
+ val[0] = a;
+ val[1] = b;
+ val[2] = c;
+ val[3] = d;
+ val[4] = e;
+ val[5] = f;
+ return new ImmutableList<T>(val);
+ }
+
+ public static <T> ImmutableList<T> copyOf(Collection<? extends T> list) {
+ return new ImmutableList<T>(list.toArray());
+ }
+
+ public static <T> ImmutableList<T> copyOf(Iterable<? extends T> iterable) {
+ List<T> list = new ArrayList<T>();
+ for (T o : iterable) list.add(o);
+ return copyOf(list);
+ }
+
+ private ImmutableList(Object[] content) {
+ this.content = content;
+ }
+
+ public ImmutableList<T> replaceElementAt(int idx, T newValue) {
+ Object[] newContent = content.clone();
+ newContent[idx] = newValue;
+ return new ImmutableList<T>(newContent);
+ }
+
+ public ImmutableList<T> append(T newValue) {
+ int len = content.length;
+ Object[] newContent = new Object[len + 1];
+ System.arraycopy(content, 0, newContent, 0, len);
+ newContent[len] = newValue;
+ return new ImmutableList<T>(newContent);
+ }
+
+ public ImmutableList<T> prepend(T newValue) {
+ int len = content.length;
+ Object[] newContent = new Object[len + 1];
+ System.arraycopy(content, 0, newContent, 1, len);
+ newContent[0] = newValue;
+ return new ImmutableList<T>(newContent);
+ }
+
+ public int indexOf(T val) {
+ int len = content.length;
+ if (val == null) {
+ for (int i = 0; i < len; i++) if (content[i] == null) return i;
+ return -1;
+ }
+
+ for (int i = 0; i < len; i++) if (val.equals(content[i])) return i;
+ return -1;
+ }
+
+ public ImmutableList<T> removeElement(T val) {
+ int idx = indexOf(val);
+ return idx == -1 ? this : removeElementAt(idx);
+ }
+
+ public ImmutableList<T> removeElementAt(int idx) {
+ int len = content.length;
+ Object[] newContent = new Object[len - 1];
+ if (idx > 0) System.arraycopy(content, 0, newContent, 0, idx);
+ if (idx < len - 1) System.arraycopy(content, idx + 1, newContent, idx, len - idx - 1);
+ return new ImmutableList<T>(newContent);
+ }
+
+ public boolean isEmpty() {
+ return content.length == 0;
+ }
+
+ public int size() {
+ return content.length;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T get(int idx) {
+ return (T) content[idx];
+ }
+
+ public boolean contains(T in) {
+ if (in == null) {
+ for (Object e : content) if (e == null) return true;
+ return false;
+ }
+
+ for (Object e : content) if (in.equals(e)) return true;
+ return false;
+ }
+
+ public Iterator<T> iterator() {
+ return new Iterator<T>() {
+ private int idx = 0;
+ @Override public boolean hasNext() {
+ return idx < content.length;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public T next() {
+ if (idx < content.length) return (T) content[idx++];
+ throw new NoSuchElementException();
+ }
+
+ @Override public void remove() {
+ throw new UnsupportedOperationException("List is immutable");
+ }
+ };
+ }
+
+ @Override public String toString() {
+ return Arrays.toString(content);
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (!(obj instanceof ImmutableList)) return false;
+ if (obj == this) return true;
+ return Arrays.equals(content, ((ImmutableList<?>) obj).content);
+ }
+
+ @Override public int hashCode() {
+ return Arrays.hashCode(content);
+ }
+}
diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java
index 301925d1..150f3a96 100644
--- a/src/utils/lombok/eclipse/Eclipse.java
+++ b/src/utils/lombok/eclipse/Eclipse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2011 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -58,7 +58,9 @@ public class Eclipse {
* but we need to deal with it. This turns [[java][lang][String]] into "java.lang.String".
*/
public static String toQualifiedName(char[][] typeName) {
- StringBuilder sb = new StringBuilder();
+ int len = typeName.length - 1;
+ for (char[] c : typeName) len += c.length;
+ StringBuilder sb = new StringBuilder(len);
boolean first = true;
for (char[] c : typeName) {
sb.append(first ? "" : ".").append(c);