aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lombok/eclipse')
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java48
-rw-r--r--src/core/lombok/eclipse/EclipseAnnotationHandler.java2
-rw-r--r--src/core/lombok/eclipse/EclipseAstProblemView.java9
-rw-r--r--src/core/lombok/eclipse/EclipseImportList.java136
-rw-r--r--src/core/lombok/eclipse/HandlerLibrary.java41
-rw-r--r--src/core/lombok/eclipse/TransformEclipseAST.java2
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java94
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java376
-rw-r--r--src/core/lombok/eclipse/handlers/HandleConstructor.java55
-rw-r--r--src/core/lombok/eclipse/handlers/HandleData.java3
-rw-r--r--src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java23
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldDefaults.java10
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java122
-rw-r--r--src/core/lombok/eclipse/handlers/HandleLog.java15
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java4
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSneakyThrows.java24
-rw-r--r--src/core/lombok/eclipse/handlers/HandleToString.java26
-rw-r--r--src/core/lombok/eclipse/handlers/HandleValue.java5
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWither.java2
-rw-r--r--src/core/lombok/eclipse/handlers/NonNullHandler.java147
20 files changed, 979 insertions, 165 deletions
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java
index 8ab42140..370b40fc 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
@@ -24,12 +24,14 @@ package lombok.eclipse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import lombok.Lombok;
import lombok.core.AST;
+import lombok.core.LombokImmutableList;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -55,7 +57,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,16 +69,18 @@ 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;
+ @Override public int getSourceVersion() {
+ long sl = compilationUnitDeclaration.problemReporter.options.sourceLevel;
+ long cl = compilationUnitDeclaration.problemReporter.options.complianceLevel;
+ sl >>= 16;
+ cl >>= 16;
+ if (sl == 0) sl = cl;
+ if (cl == 0) cl = sl;
+ return Math.min((int)(sl - 44), (int)(cl - 44));
+ }
+
+ @Override public int getLatestJavaSpecSupported() {
+ return Eclipse.getEcjCompilerVersion();
}
/**
@@ -88,8 +92,10 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
}
void traverseChildren(EclipseASTVisitor visitor, EclipseNode node) {
- for (EclipseNode child : node.down()) {
- child.traverse(visitor);
+ LombokImmutableList<EclipseNode> children = node.down();
+ int len = children.size();
+ for (int i = 0; i < len; i++) {
+ children.get(i).traverse(visitor);
}
}
@@ -118,7 +124,8 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
}
void addToCompilationResult() {
- addProblemToCompilationResult((CompilationUnitDeclaration) top().get(),
+ CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().get();
+ addProblemToCompilationResult(cud.getFileName(), cud.compilationResult,
isWarning, message, sourceStart, sourceEnd);
}
}
@@ -142,11 +149,10 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
* Adds a problem to the provided CompilationResult object so that it will show up
* in the Problems/Warnings view.
*/
- public static void addProblemToCompilationResult(CompilationUnitDeclaration ast,
+ public static void addProblemToCompilationResult(char[] fileNameArray, CompilationResult result,
boolean isWarning, String message, int sourceStart, int sourceEnd) {
- if (ast.compilationResult == null) return;
try {
- EcjReflectionCheck.addProblemToCompilationResult.invoke(null, ast, isWarning, message, sourceStart, sourceEnd);
+ EcjReflectionCheck.addProblemToCompilationResult.invoke(null, fileNameArray, result, isWarning, message, sourceStart, sourceEnd);
} catch (NoClassDefFoundError e) {
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
//do anything useful here.
@@ -163,7 +169,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
//do anything useful here.
}
}
-
+
private final CompilationUnitDeclaration compilationUnitDeclaration;
private boolean completeParse;
@@ -353,7 +359,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
}
private static class EcjReflectionCheck {
- private static final String CUD_TYPE = "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration";
+ private static final String COMPILATIONRESULT_TYPE = "org.eclipse.jdt.internal.compiler.CompilationResult";
public static Method addProblemToCompilationResult;
public static final Throwable problem;
@@ -362,7 +368,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
Throwable problem_ = null;
Method m = null;
try {
- m = EclipseAstProblemView.class.getMethod("addProblemToCompilationResult", Class.forName(CUD_TYPE), boolean.class, String.class, int.class, int.class);
+ m = EclipseAstProblemView.class.getMethod("addProblemToCompilationResult", char[].class, Class.forName(COMPILATIONRESULT_TYPE), boolean.class, String.class, int.class, int.class);
} catch (Throwable t) {
// That's problematic, but as long as no local classes are used we don't actually need it.
// Better fail on local classes than crash altogether.
diff --git a/src/core/lombok/eclipse/EclipseAnnotationHandler.java b/src/core/lombok/eclipse/EclipseAnnotationHandler.java
index 84304339..ca9965f7 100644
--- a/src/core/lombok/eclipse/EclipseAnnotationHandler.java
+++ b/src/core/lombok/eclipse/EclipseAnnotationHandler.java
@@ -29,7 +29,7 @@ import lombok.core.SpiLoadUtil;
*
* You MUST replace 'T' with a specific annotation type, such as:
*
- * {@code public class HandleGetter implements EclipseAnnotationHandler<Getter>}
+ * {@code public class HandleGetter extends EclipseAnnotationHandler<Getter>}
*
* Because this generics parameter is inspected to figure out which class you're interested in.
*
diff --git a/src/core/lombok/eclipse/EclipseAstProblemView.java b/src/core/lombok/eclipse/EclipseAstProblemView.java
index a2d5b833..c1179666 100644
--- a/src/core/lombok/eclipse/EclipseAstProblemView.java
+++ b/src/core/lombok/eclipse/EclipseAstProblemView.java
@@ -3,7 +3,6 @@ package lombok.eclipse;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.Util;
@@ -13,14 +12,12 @@ public class EclipseAstProblemView {
* Adds a problem to the provided CompilationResult object so that it will show up
* in the Problems/Warnings view.
*/
- public static void addProblemToCompilationResult(CompilationUnitDeclaration ast,
+ public static void addProblemToCompilationResult(char[] fileNameArray, CompilationResult result,
boolean isWarning, String message, int sourceStart, int sourceEnd) {
- if (ast.compilationResult == null) return;
- char[] fileNameArray = ast.getFileName();
+ if (result == null) return;
if (fileNameArray == null) fileNameArray = "(unknown).java".toCharArray();
int lineNumber = 0;
int columnNumber = 1;
- CompilationResult result = ast.compilationResult;
int[] lineEnds = null;
lineNumber = sourceStart >= 0
? Util.getLineNumber(sourceStart, lineEnds = result.getLineSeparatorPositions(), 0, lineEnds.length-1)
@@ -33,7 +30,7 @@ public class EclipseAstProblemView {
fileNameArray, message, 0, new String[0],
isWarning ? ProblemSeverities.Warning : ProblemSeverities.Error,
sourceStart, sourceEnd, lineNumber, columnNumber);
- ast.compilationResult.record(ecProblem, null);
+ result.record(ecProblem, null);
}
private static class LombokProblem extends DefaultProblem {
diff --git a/src/core/lombok/eclipse/EclipseImportList.java b/src/core/lombok/eclipse/EclipseImportList.java
new file mode 100644
index 00000000..69246b3c
--- /dev/null
+++ b/src/core/lombok/eclipse/EclipseImportList.java
@@ -0,0 +1,136 @@
+/*
+ * 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.toQualifiedName;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import lombok.core.ImportList;
+import lombok.core.LombokInternalAliasing;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+
+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 LombokInternalAliasing.processAliases(toQualifiedName(tokens));
+ }
+ }
+ return null;
+ }
+
+ @Override public boolean hasStarImport(String packageName) {
+ for (Map.Entry<String, String> e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) {
+ if (e.getValue().equals(packageName) && hasStarImport(e.getKey())) return true;
+ }
+ 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/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java
index 47e620f6..11caf5c2 100644
--- a/src/core/lombok/eclipse/TransformEclipseAST.java
+++ b/src/core/lombok/eclipse/TransformEclipseAST.java
@@ -144,7 +144,7 @@ public class TransformEclipseAST {
try {
String message = "Lombok can't parse this source: " + t.toString();
- EclipseAST.addProblemToCompilationResult(ast, false, message, 0, 0);
+ EclipseAST.addProblemToCompilationResult(ast.getFileName(), ast.compilationResult, false, message, 0, 0);
t.printStackTrace();
} catch (Throwable t2) {
try {
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 78780522..9bd634f7 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -22,6 +22,7 @@
package lombok.eclipse.handlers;
import static lombok.eclipse.Eclipse.*;
+import static lombok.core.TransformationsUtil.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -61,6 +62,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Block;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
@@ -142,7 +144,7 @@ public class EclipseHandlerUtil {
} catch (NoClassDefFoundError e) { //standalone ecj does not jave Platform, ILog, IStatus, and friends.
new TerminalLogger().error(message, bundleName, error);
}
- if (cud != null) EclipseAST.addProblemToCompilationResult(cud, false, message + " - See error log.", 0, 0);
+ if (cud != null) EclipseAST.addProblemToCompilationResult(cud.getFileName(), cud.compilationResult, false, message + " - See error log.", 0, 0);
}
/**
@@ -290,11 +292,34 @@ 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);
}
+ public static void sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(EclipseNode typeNode, EclipseNode errorNode) {
+ List<String> disallowed = null;
+ for (EclipseNode child : typeNode.down()) {
+ for (Class<? extends java.lang.annotation.Annotation> annType : INVALID_ON_BUILDERS) {
+ if (annotationTypeMatches(annType, child)) {
+ if (disallowed == null) disallowed = new ArrayList<String>();
+ disallowed.add(annType.getSimpleName());
+ }
+ }
+ }
+
+ int size = disallowed == null ? 0 : disallowed.size();
+ if (size == 0) return;
+ if (size == 1) {
+ errorNode.addError("@" + disallowed.get(0) + " is not allowed on builder classes.");
+ return;
+ }
+ StringBuilder out = new StringBuilder();
+ for (String a : disallowed) out.append("@").append(a).append(", ");
+ out.setLength(out.length() - 2);
+ errorNode.addError(out.append(" are not allowed on builder classes.").toString());
+ }
+
public static Annotation copyAnnotation(Annotation annotation, ASTNode source) {
int pS = source.sourceStart, pE = source.sourceEnd;
@@ -358,6 +383,20 @@ public class EclipseHandlerUtil {
return out;
}
+ public static TypeReference namePlusTypeParamsToTypeReference(char[] typeName, TypeParameter[] params, long p) {
+ if (params != null && params.length > 0) {
+ TypeReference[] refs = new TypeReference[params.length];
+ int idx = 0;
+ for (TypeParameter param : params) {
+ TypeReference typeRef = new SingleTypeReference(param.name, p);
+ refs[idx++] = typeRef;
+ }
+ return new ParameterizedSingleTypeReference(typeName, refs, 0, p);
+ }
+
+ return new SingleTypeReference(typeName, p);
+ }
+
/**
* Convenience method that creates a new array and copies each TypeReference in the source array via
* {@link #copyType(TypeReference, ASTNode)}.
@@ -830,15 +869,20 @@ public class EclipseHandlerUtil {
private static final Object MARKER = new Object();
static void registerCreatedLazyGetter(FieldDeclaration field, char[] methodName, TypeReference returnType) {
- if (!nameEquals(returnType.getTypeName(), "boolean") || returnType.dimensions() > 0) return;
- generatedLazyGettersWithPrimitiveBoolean.put(field, MARKER);
+ if (isBoolean(returnType)) {
+ generatedLazyGettersWithPrimitiveBoolean.put(field, MARKER);
+ }
+ }
+
+ public static boolean isBoolean(TypeReference typeReference) {
+ return nameEquals(typeReference.getTypeName(), "boolean") && typeReference.dimensions() == 0;
}
private static GetterMethod findGetter(EclipseNode field) {
FieldDeclaration fieldDeclaration = (FieldDeclaration) field.get();
boolean forceBool = generatedLazyGettersWithPrimitiveBoolean.containsKey(fieldDeclaration);
TypeReference fieldType = fieldDeclaration.type;
- boolean isBoolean = forceBool || (nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0);
+ boolean isBoolean = forceBool || isBoolean(fieldType);
EclipseNode typeNode = field.up();
for (String potentialGetterName : toAllGetterNames(field, isBoolean)) {
@@ -1207,15 +1251,15 @@ public class EclipseHandlerUtil {
* Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}.
* The field carries the &#64;{@link SuppressWarnings}("all") annotation.
*/
- public static void injectFieldSuppressWarnings(EclipseNode type, FieldDeclaration field) {
+ public static EclipseNode injectFieldSuppressWarnings(EclipseNode type, FieldDeclaration field) {
field.annotations = createSuppressWarningsAll(field, field.annotations);
- injectField(type, field);
+ return injectField(type, field);
}
/**
* Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}.
*/
- public static void injectField(EclipseNode type, FieldDeclaration field) {
+ public static EclipseNode injectField(EclipseNode type, FieldDeclaration field) {
TypeDeclaration parent = (TypeDeclaration) type.get();
if (parent.fields == null) {
@@ -1242,7 +1286,7 @@ public class EclipseHandlerUtil {
}
}
- type.add(field, Kind.FIELD);
+ return type.add(field, Kind.FIELD);
}
private static boolean isEnumConstant(final FieldDeclaration field) {
@@ -1252,7 +1296,7 @@ public class EclipseHandlerUtil {
/**
* Inserts a method into an existing type. The type must represent a {@code TypeDeclaration}.
*/
- public static void injectMethod(EclipseNode type, AbstractMethodDeclaration method) {
+ public static EclipseNode injectMethod(EclipseNode type, AbstractMethodDeclaration method) {
method.annotations = createSuppressWarningsAll(method, method.annotations);
TypeDeclaration parent = (TypeDeclaration) type.get();
@@ -1285,7 +1329,29 @@ public class EclipseHandlerUtil {
parent.methods = newArray;
}
- type.add(method, Kind.METHOD);
+ return type.add(method, Kind.METHOD);
+ }
+
+ /**
+ * Adds an inner type (class, interface, enum) to the given type. Cannot inject top-level types.
+ *
+ * @param typeNode parent type to inject new type into
+ * @param type New type (class, interface, etc) to inject.
+ */
+ public static EclipseNode injectType(final EclipseNode typeNode, final TypeDeclaration type) {
+ type.annotations = createSuppressWarningsAll(type, type.annotations);
+ TypeDeclaration parent = (TypeDeclaration) typeNode.get();
+
+ if (parent.memberTypes == null) {
+ parent.memberTypes = new TypeDeclaration[] { type };
+ } else {
+ TypeDeclaration[] newArray = new TypeDeclaration[parent.memberTypes.length + 1];
+ System.arraycopy(parent.memberTypes, 0, newArray, 0, parent.memberTypes.length);
+ newArray[parent.memberTypes.length] = type;
+ parent.memberTypes = newArray;
+ }
+
+ return typeNode.add(type, Kind.TYPE);
}
private static final char[] ALL = "all".toCharArray();
@@ -1334,7 +1400,11 @@ public class EclipseHandlerUtil {
EqualExpression equalExpression = new EqualExpression(varName, nullLiteral, OperatorIds.EQUAL_EQUAL);
equalExpression.sourceStart = pS; equalExpression.statementEnd = equalExpression.sourceEnd = pE;
setGeneratedBy(equalExpression, source);
- IfStatement ifStatement = new IfStatement(equalExpression, throwStatement, 0, 0);
+ Block throwBlock = new Block(0);
+ throwBlock.statements = new Statement[] {throwStatement};
+ throwBlock.sourceStart = pS; throwBlock.sourceEnd = pE;
+ setGeneratedBy(throwBlock, source);
+ IfStatement ifStatement = new IfStatement(equalExpression, throwBlock, 0, 0);
setGeneratedBy(ifStatement, source);
return ifStatement;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
new file mode 100644
index 00000000..70110a9c
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -0,0 +1,376 @@
+/*
+ * 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.handlers;
+
+import static lombok.eclipse.Eclipse.*;
+import static lombok.core.handlers.HandlerUtil.*;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.mangosdk.spi.ProviderFor;
+
+import lombok.AccessLevel;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.core.HandlerPriority;
+import lombok.core.TransformationsUtil;
+import lombok.eclipse.Eclipse;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseNode;
+import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists;
+import lombok.experimental.Builder;
+import lombok.experimental.NonFinal;
+
+@ProviderFor(EclipseAnnotationHandler.class)
+@HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes.
+public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
+ @Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
+ long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
+
+ Builder builderInstance = annotation.getInstance();
+ String builderMethodName = builderInstance.builderMethodName();
+ String buildMethodName = builderInstance.buildMethodName();
+ String builderClassName = builderInstance.builderClassName();
+
+ if (builderMethodName == null) builderMethodName = "builder";
+ if (buildMethodName == null) builderMethodName = "build";
+ if (builderClassName == null) builderClassName = "";
+
+ if (!checkName("builderMethodName", builderMethodName, annotationNode)) return;
+ if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
+ if (!builderClassName.isEmpty()) {
+ if (!checkName("builderClassName", builderClassName, annotationNode)) return;
+ }
+
+ EclipseNode parent = annotationNode.up();
+
+ List<TypeReference> typesOfParameters = new ArrayList<TypeReference>();
+ List<char[]> namesOfParameters = new ArrayList<char[]>();
+ TypeReference returnType;
+ TypeParameter[] typeParams;
+ TypeReference[] thrownExceptions;
+ char[] nameOfStaticBuilderMethod;
+ EclipseNode tdParent;
+
+ AbstractMethodDeclaration fillParametersFrom = null;
+
+ if (parent.get() instanceof TypeDeclaration) {
+ tdParent = parent;
+ TypeDeclaration td = (TypeDeclaration) tdParent.get();
+
+ List<EclipseNode> fields = new ArrayList<EclipseNode>();
+ @SuppressWarnings("deprecation")
+ boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent));
+ for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent)) {
+ FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
+ // final fields with an initializer cannot be written to, so they can't be 'builderized'. Unfortunately presence of @Value makes
+ // non-final fields final, but @Value's handler hasn't done this yet, so we have to do this math ourselves.
+ // Value will only skip making a field final if it has an explicit @NonFinal annotation, so we check for that.
+ if (fd.initialization != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue;
+ namesOfParameters.add(fd.name);
+ typesOfParameters.add(fd.type);
+ fields.add(fieldNode);
+ }
+
+ new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, fields, null, SkipIfConstructorExists.I_AM_BUILDER, true, Collections.<Annotation>emptyList(), ast);
+
+ returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
+ typeParams = td.typeParameters;
+ thrownExceptions = null;
+ nameOfStaticBuilderMethod = null;
+ if (builderClassName.isEmpty()) builderClassName = new String(td.name) + "Builder";
+ } else if (parent.get() instanceof ConstructorDeclaration) {
+ ConstructorDeclaration cd = (ConstructorDeclaration) parent.get();
+ if (cd.typeParameters != null && cd.typeParameters.length > 0) {
+ annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
+ return;
+ }
+
+ tdParent = parent.up();
+ TypeDeclaration td = (TypeDeclaration) tdParent.get();
+ fillParametersFrom = cd;
+ returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
+ typeParams = td.typeParameters;
<