aboutsummaryrefslogtreecommitdiff
path: root/src/lombok/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'src/lombok/eclipse')
-rw-r--r--src/lombok/eclipse/Eclipse.java23
-rw-r--r--src/lombok/eclipse/EclipseAST.java70
-rw-r--r--src/lombok/eclipse/EclipseASTVisitor.java4
-rw-r--r--src/lombok/eclipse/HandlerLibrary.java12
-rw-r--r--src/lombok/eclipse/TransformEclipseAST.java11
-rw-r--r--src/lombok/eclipse/handlers/HandleData.java127
-rw-r--r--src/lombok/eclipse/handlers/HandleGetter.java66
-rw-r--r--src/lombok/eclipse/handlers/HandleSetter.java92
-rw-r--r--src/lombok/eclipse/handlers/PKG.java64
9 files changed, 357 insertions, 112 deletions
diff --git a/src/lombok/eclipse/Eclipse.java b/src/lombok/eclipse/Eclipse.java
index baac26a9..a7286058 100644
--- a/src/lombok/eclipse/Eclipse.java
+++ b/src/lombok/eclipse/Eclipse.java
@@ -19,37 +19,45 @@ import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.Literal;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.osgi.framework.Bundle;
public class Eclipse {
+ public static final int ECLIPSE_DO_NOT_TOUCH_FLAG = ASTNode.Bit24;
private Eclipse() {
//Prevent instantiation
}
private static final String DEFAULT_BUNDLE = "org.eclipse.jdt.core";
- public static void error(String message) {
- error(message, DEFAULT_BUNDLE, null);
+ public static final TypeReference TYPEREF_JAVA_LANG_STRING = new QualifiedTypeReference(
+ TypeConstants.JAVA_LANG_STRING, new long[] {0, 0, 0});
+
+ public static void error(CompilationUnitDeclaration cud, String message) {
+ error(cud, message, DEFAULT_BUNDLE, null);
}
- public static void error(String message, Throwable error) {
- error(message, DEFAULT_BUNDLE, error);
+ public static void error(CompilationUnitDeclaration cud, String message, Throwable error) {
+ error(cud, message, DEFAULT_BUNDLE, error);
}
- public static void error(String message, String bundleName) {
- error(message, bundleName, null);
+ public static void error(CompilationUnitDeclaration cud, String message, String bundleName) {
+ error(cud, message, bundleName, null);
}
- public static void error(String message, String bundleName, Throwable error) {
+ public static void error(CompilationUnitDeclaration cud, String message, String bundleName, Throwable error) {
Bundle bundle = Platform.getBundle(bundleName);
if ( bundle == null ) {
System.err.printf("Can't find bundle %s while trying to report error:\n%s\n", bundleName, message);
@@ -59,6 +67,7 @@ public class Eclipse {
ILog log = Platform.getLog(bundle);
log.log(new Status(IStatus.ERROR, bundleName, message, error));
+ if ( cud != null ) EclipseAST.addProblemToCompilationResult(cud, false, message + " - See error log.", 0, 0);
}
static String toQualifiedName(char[][] typeName) {
diff --git a/src/lombok/eclipse/EclipseAST.java b/src/lombok/eclipse/EclipseAST.java
index 6c4ce211..850fb8dc 100644
--- a/src/lombok/eclipse/EclipseAST.java
+++ b/src/lombok/eclipse/EclipseAST.java
@@ -70,21 +70,19 @@ public class EclipseAST extends AST<ASTNode> {
private class ParseProblem {
final boolean isWarning;
final String message;
- final Node node;
final int sourceStart;
final int sourceEnd;
- public ParseProblem(boolean isWarning, String message, Node node, int sourceStart, int sourceEnd) {
+ public ParseProblem(boolean isWarning, String message, int sourceStart, int sourceEnd) {
this.isWarning = isWarning;
this.message = message;
- this.node = node;
this.sourceStart = sourceStart;
this.sourceEnd = sourceEnd;
}
void addToCompilationResult() {
- addProblemToCompilationResult(getFileName(), (CompilationUnitDeclaration) top().get(),
- isWarning, message, node.get(), sourceStart, sourceEnd);
+ addProblemToCompilationResult((CompilationUnitDeclaration) top().get(),
+ isWarning, message, sourceStart, sourceEnd);
}
}
@@ -103,9 +101,11 @@ public class EclipseAST extends AST<ASTNode> {
propagateProblems();
}
- static void addProblemToCompilationResult(String fileName, CompilationUnitDeclaration ast,
- boolean isWarning, String message, ASTNode node, int sourceStart, int sourceEnd) {
- char[] fileNameArray = fileName.toCharArray();
+ static void addProblemToCompilationResult(CompilationUnitDeclaration ast,
+ boolean isWarning, String message, int sourceStart, int sourceEnd) {
+ if ( ast.compilationResult == null ) return;
+ char[] fileNameArray = ast.getFileName();
+ if ( fileNameArray == null ) fileNameArray = "(unknown).java".toCharArray();
int lineNumber = 0;
int columnNumber = 1;
CompilationResult result = ast.compilationResult;
@@ -218,7 +218,7 @@ public class EclipseAST extends AST<ASTNode> {
}
public void addError(String message, int sourceStart, int sourceEnd) {
- addProblem(new ParseProblem(false, message, this, sourceStart, sourceEnd));
+ addProblem(new ParseProblem(false, message, sourceStart, sourceEnd));
}
@Override public void addWarning(String message) {
@@ -226,7 +226,7 @@ public class EclipseAST extends AST<ASTNode> {
}
public void addWarning(String message, int sourceStart, int sourceEnd) {
- addProblem(new ParseProblem(true, message, this, sourceStart, sourceEnd));
+ addProblem(new ParseProblem(true, message, sourceStart, sourceEnd));
}
/** {@inheritDoc} */
@@ -244,6 +244,11 @@ public class EclipseAST extends AST<ASTNode> {
}
/** {@inheritDoc} */
+ @Override public Node getNodeFor(ASTNode obj) {
+ return (Node) super.getNodeFor(obj);
+ }
+
+ /** {@inheritDoc} */
public Node directUp() {
return (Node) super.directUp();
}
@@ -300,6 +305,31 @@ public class EclipseAST extends AST<ASTNode> {
return (unit.bits & ASTNode.HasAllMethodBodies) > 0;
}
+ @Override protected Node buildTree(ASTNode node, Kind kind) {
+ switch ( kind ) {
+ case COMPILATION_UNIT:
+ return buildCompilationUnit((CompilationUnitDeclaration) node);
+ case TYPE:
+ return buildType((TypeDeclaration) node);
+ case FIELD:
+ return buildField((FieldDeclaration) node);
+ case INITIALIZER:
+ return buildInitializer((Initializer) node);
+ case METHOD:
+ return buildMethod((AbstractMethodDeclaration) node);
+ case ARGUMENT:
+ return buildLocal((Argument) node, kind);
+ case LOCAL:
+ return buildLocal((LocalDeclaration) node, kind);
+ case STATEMENT:
+ return buildStatement((Statement) node);
+ case ANNOTATION:
+ return buildAnnotation((Annotation) node);
+ default:
+ throw new AssertionError("Did not expect to arrive here: " + kind);
+ }
+ }
+
private Node buildCompilationUnit(CompilationUnitDeclaration top) {
Collection<Node> children = buildTypes(top.types);
return putInMap(new Node(top, children, Kind.COMPILATION_UNIT));
@@ -373,30 +403,32 @@ public class EclipseAST extends AST<ASTNode> {
if ( children == null ) return Collections.emptyList();
List<Node> childNodes = new ArrayList<Node>();
for ( LocalDeclaration local : children ) {
- addIfNotNull(childNodes, buildLocal(local));
+ addIfNotNull(childNodes, buildLocal(local, Kind.ARGUMENT));
}
return childNodes;
}
- private Node buildLocal(LocalDeclaration local) {
+ private Node buildLocal(LocalDeclaration local, Kind kind) {
if ( alreadyHandled(local) ) return null;
List<Node> childNodes = new ArrayList<Node>();
addIfNotNull(childNodes, buildStatement(local.initialization));
childNodes.addAll(buildAnnotations(local.annotations));
- return putInMap(new Node(local, childNodes, Kind.LOCAL));
+ return putInMap(new Node(local, childNodes, kind));
}
private Collection<Node> buildAnnotations(Annotation[] annotations) {
if ( annotations == null ) return Collections.emptyList();
List<Node> elements = new ArrayList<Node>();
- for ( Annotation an : annotations ) {
- if ( an == null ) continue;
- if ( alreadyHandled(an) ) continue;
- elements.add(putInMap(new Node(an, null, Kind.ANNOTATION)));
- }
+ for ( Annotation an : annotations ) addIfNotNull(elements, buildAnnotation(an));
return elements;
}
+ private Node buildAnnotation(Annotation annotation) {
+ if ( annotation == null ) return null;
+ if ( alreadyHandled(annotation) ) return null;
+ return putInMap(new Node(annotation, null, Kind.ANNOTATION));
+ }
+
private Collection<Node> buildStatements(Statement[] children) {
if ( children == null ) return Collections.emptyList();
List<Node> childNodes = new ArrayList<Node>();
@@ -409,7 +441,7 @@ public class EclipseAST extends AST<ASTNode> {
if ( child == null || alreadyHandled(child) ) return null;
if ( child instanceof TypeDeclaration ) return buildType((TypeDeclaration)child);
- if ( child instanceof LocalDeclaration ) return buildLocal((LocalDeclaration)child);
+ if ( child instanceof LocalDeclaration ) return buildLocal((LocalDeclaration)child, Kind.LOCAL);
//We drill down because LocalDeclarations and TypeDeclarations can occur anywhere, even in, say,
//an if block, or even the expression on an assert statement!
diff --git a/src/lombok/eclipse/EclipseASTVisitor.java b/src/lombok/eclipse/EclipseASTVisitor.java
index d5fece8f..aac0d8ed 100644
--- a/src/lombok/eclipse/EclipseASTVisitor.java
+++ b/src/lombok/eclipse/EclipseASTVisitor.java
@@ -122,8 +122,8 @@ public interface EclipseASTVisitor {
}
@Override public void visitCompilationUnit(Node node, CompilationUnitDeclaration unit) {
- System.out.println("---------------------------------------------------------");
- System.out.println(node.isCompleteParse() ? "COMPLETE" : "incomplete");
+ out.println("---------------------------------------------------------");
+ out.println(node.isCompleteParse() ? "COMPLETE" : "incomplete");
print("<CUD %s>", node.getFileName());
indent++;
diff --git a/src/lombok/eclipse/HandlerLibrary.java b/src/lombok/eclipse/HandlerLibrary.java
index 39864e8e..10180963 100644
--- a/src/lombok/eclipse/HandlerLibrary.java
+++ b/src/lombok/eclipse/HandlerLibrary.java
@@ -63,11 +63,11 @@ public class HandlerLibrary {
SpiLoadUtil.findAnnotationClass(handler.getClass(), EclipseAnnotationHandler.class);
AnnotationHandlerContainer<?> container = new AnnotationHandlerContainer(handler, annotationClass);
if ( lib.annotationHandlers.put(container.annotationClass.getName(), container) != null ) {
- Eclipse.error("Duplicate handlers for annotation type: " + container.annotationClass.getName());
+ Eclipse.error(null, "Duplicate handlers for annotation type: " + container.annotationClass.getName());
}
lib.typeLibrary.addType(container.annotationClass.getName());
} catch ( ServiceConfigurationError e ) {
- Eclipse.error("Can't load Lombok annotation handler for eclipse: ", e);
+ Eclipse.error(null, "Can't load Lombok annotation handler for eclipse: ", e);
}
}
}
@@ -78,7 +78,7 @@ public class HandlerLibrary {
try {
lib.visitorHandlers.add(it.next());
} catch ( ServiceConfigurationError e ) {
- Eclipse.error("Can't load Lombok visitor handler for eclipse: ", e);
+ Eclipse.error(null, "Can't load Lombok visitor handler for eclipse: ", e);
}
}
}
@@ -94,6 +94,7 @@ public class HandlerLibrary {
boolean handled = false;
for ( String fqn : resolver.findTypeMatches(annotationNode, toQualifiedName(annotation.type.getTypeName())) ) {
AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
+
if ( container == null ) continue;
try {
@@ -101,7 +102,7 @@ public class HandlerLibrary {
} catch ( AnnotationValueDecodeFail fail ) {
fail.owner.setError(fail.getMessage(), fail.idx);
} catch ( Throwable t ) {
- Eclipse.error(String.format("Lombok annotation handler %s failed", container.handler.getClass()), t);
+ Eclipse.error(ast, String.format("Lombok annotation handler %s failed", container.handler.getClass()), t);
}
}
@@ -112,7 +113,8 @@ public class HandlerLibrary {
for ( EclipseASTVisitor visitor : visitorHandlers ) try {
ast.traverse(visitor);
} catch ( Throwable t ) {
- Eclipse.error(String.format("Lombok visitor handler %s failed", visitor.getClass()), t);
+ Eclipse.error((CompilationUnitDeclaration) ast.top().get(),
+ String.format("Lombok visitor handler %s failed", visitor.getClass()), t);
}
}
}
diff --git a/src/lombok/eclipse/TransformEclipseAST.java b/src/lombok/eclipse/TransformEclipseAST.java
index b56c594a..ccb29a8c 100644
--- a/src/lombok/eclipse/TransformEclipseAST.java
+++ b/src/lombok/eclipse/TransformEclipseAST.java
@@ -41,7 +41,7 @@ public class TransformEclipseAST {
l = HandlerLibrary.load();
f = CompilationUnitDeclaration.class.getDeclaredField("$lombokAST");
} catch ( Throwable t ) {
- Eclipse.error("Problem initializing lombok", t);
+ Eclipse.error(null, "Problem initializing lombok", t);
disableLombok = true;
}
astCacheField = f;
@@ -70,17 +70,12 @@ public class TransformEclipseAST {
new TransformEclipseAST(existing).go();
} catch ( Throwable t ) {
try {
- String fileName = "(unknown)";
- if ( ast.compilationResult != null && ast.compilationResult.fileName != null ) {
- fileName = new String(ast.compilationResult.fileName);
- }
-
String message = "Lombok can't parse this source: " + t.toString();
- EclipseAST.addProblemToCompilationResult(fileName, ast, false, message, ast, 0, 0);
+ EclipseAST.addProblemToCompilationResult(ast, false, message, 0, 0);
t.printStackTrace();
} catch ( Throwable t2 ) {
- Eclipse.error("Can't create an error in the problems dialog while adding: " + t.toString(), t2);
+ Eclipse.error(ast, "Can't create an error in the problems dialog while adding: " + t.toString(), t2);
}
}
}
diff --git a/src/lombok/eclipse/handlers/HandleData.java b/src/lombok/eclipse/handlers/HandleData.java
index 64540e95..6c77644f 100644
--- a/src/lombok/eclipse/handlers/HandleData.java
+++ b/src/lombok/eclipse/handlers/HandleData.java
@@ -1,20 +1,38 @@
package lombok.eclipse.handlers;
+import static lombok.eclipse.handlers.PKG.*;
+
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
-import org.eclipse.jdt.internal.compiler.ast.Annotation;
-import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
-import org.mangosdk.spi.ProviderFor;
-
+import lombok.AccessLevel;
import lombok.Data;
import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
+import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseAST.Node;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
+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.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
+import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.mangosdk.spi.ProviderFor;
+
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleData implements EclipseAnnotationHandler<Data> {
@Override public boolean handle(AnnotationValues<Data> annotation, Annotation ast, Node annotationNode) {
@@ -32,18 +50,111 @@ public class HandleData implements EclipseAnnotationHandler<Data> {
}
List<Node> nodesForEquality = new ArrayList<Node>();
+ List<Node> nodesForConstructorAndToString = new ArrayList<Node>();
for ( Node child : typeNode.down() ) {
if ( child.getKind() != Kind.FIELD ) continue;
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
//Skip static fields.
if ( (fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0 ) continue;
if ( (fieldDecl.modifiers & ClassFileConstants.AccTransient) == 0 ) nodesForEquality.add(child);
+ nodesForConstructorAndToString.add(child);
new HandleGetter().generateGetterForField(child, annotationNode.get());
if ( (fieldDecl.modifiers & ClassFileConstants.AccFinal) == 0 )
new HandleSetter().generateSetterForField(child, annotationNode.get());
}
- //TODO generate constructor, hashCode, equals, toString.
- return true;
+ switch ( methodExists("toString", typeNode) ) {
+ case NOT_EXISTS:
+ MethodDeclaration toString = createToString(typeNode, nodesForConstructorAndToString, ast);
+ injectMethod(typeNode, toString);
+ break;
+ case EXISTS_BY_LOMBOK:
+ injectScopeIntoToString((MethodDeclaration) getExistingLombokMethod("toString", typeNode).get(), typeDecl);
+ }
+
+ //TODO generate constructor, hashCode, equals.
+ return false;
+ }
+
+ private void injectScopeIntoToString(MethodDeclaration method, TypeDeclaration typeDecl) {
+ if ( typeDecl.scope != null ) {
+ method.scope = new MethodScope(typeDecl.scope, method, false);
+ method.returnType.resolvedType = typeDecl.scope.getJavaLangString();
+ method.binding = new MethodBinding(method.modifiers,
+ method.selector, typeDecl.scope.getJavaLangString(), null, null, typeDecl.binding);
+ }
+ }
+
+ private MethodDeclaration createToString(Node type, Collection<Node> fields, ASTNode pos) {
+ char[] rawTypeName = ((TypeDeclaration)type.get()).name;
+ String typeName = rawTypeName == null ? "" : new String(rawTypeName);
+ char[] prefix = (typeName + "(").toCharArray();
+ char[] suffix = ")".toCharArray();
+ char[] infix = ", ".toCharArray();
+ long p = (long)pos.sourceStart << 32 | pos.sourceEnd;
+ final int PLUS = OperatorIds.PLUS;
+
+ boolean first = true;
+ Expression current = new StringLiteral(prefix, 0, 0, 0);
+ for ( Node field : fields ) {
+ char[] fName = ((FieldDeclaration)field.get()).name;
+ if ( fName == null ) continue;
+ if ( !first ) {
+ current = new BinaryExpression(current, new StringLiteral(infix, 0, 0, 0), PLUS);
+ }
+ else first = false;
+ current = new BinaryExpression(current, new SingleNameReference(fName, p), PLUS);
+ }
+ current = new BinaryExpression(current, new StringLiteral(suffix, 0, 0, 0), PLUS);
+
+ ReturnStatement returnStatement = new ReturnStatement(current, (int)(p >> 32), (int)p);
+
+ MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ method.modifiers = PKG.toModifier(AccessLevel.PUBLIC);
+ method.returnType = Eclipse.TYPEREF_JAVA_LANG_STRING;
+ method.annotations = null;
+ method.arguments = null;
+ method.selector = "toString".toCharArray();
+ method.binding = null;
+ method.thrownExceptions = null;
+ method.typeParameters = null;
+ injectScopeIntoToString(method, (TypeDeclaration) type.get());
+ method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ method.bodyStart = method.declarationSourceStart = method.sourceStart = pos.sourceStart;
+ method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = pos.sourceEnd;
+ method.statements = new Statement[] { returnStatement };
+ return method;
+ }
+
+ private MethodDeclaration createEquals(Collection<Node> fields) {
+ return null;
+ }
+
+ private ConstructorDeclaration createConstructor(Collection<Node> fields) {
+ //If using an of() constructor, make private.
+ //method params
+ //on loop: Assignment(FieldReference(ThisReference, "x"), SingleNameReference("x"))
+ return null;
+ }
+
+ private MethodDeclaration createStaticConstructor(Collection<Node> fields) {
+ //Return(AllocationExpression(SingleTypeReference("Bar"), namesOfFields);
+ return null;
+ }
+
+ private MethodDeclaration createHashCode(Collection<Node> fields) {
+ //booleans: conditionalexpression that bounces between 1231 and 1237.
+ //longs: (int) (lng ^ (lng >>> 32));
+ //doubles and floats: Double.doubleToLongBits, then as long.
+
+ //local final var PRIME = IntLiteral(primeNumber)
+ //local final var RESULT = IntLiteral(1)
+
+ // Assignment("RESULT", BinaryExpression("+", BinaryExpression("*", "PRIME", "RESULT"), "name")
+
+ // add = ConditionalExpression(EqualExpression("name", NullLiteral), IntLiteral(0), MessageSend("name", "hashCode()"))
+ // Assignment("RESULT", BinaryExpression("+", BinaryExpression("*", "PRIME", "RESULT"), add);
+
+ return null;
}
}
diff --git a/src/lombok/eclipse/handlers/HandleGetter.java b/src/lombok/eclipse/handlers/HandleGetter.java
index 798705da..5b3fbf90 100644
--- a/src/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/lombok/eclipse/handlers/HandleGetter.java
@@ -1,18 +1,17 @@
package lombok.eclipse.handlers;
import static lombok.eclipse.handlers.PKG.*;
-
import lombok.AccessLevel;
import lombok.Getter;
import lombok.core.AnnotationValues;
import lombok.core.TransformationsUtil;
import lombok.core.AST.Kind;
import lombok.eclipse.Eclipse;
+import lombok.eclipse.EclipseASTVisitor;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseAST.Node;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
@@ -23,14 +22,16 @@ import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.mangosdk.spi.ProviderFor;
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleGetter implements EclipseAnnotationHandler<Getter> {
public void generateGetterForField(Node fieldNode, ASTNode pos) {
- AccessLevel level = Getter.DEFAULT_ACCESS_LEVEL;
+ AccessLevel level = AccessLevel.PUBLIC;
Node errorNode = fieldNode;
+ boolean whineIfExists = false;
for ( Node child : fieldNode.down() ) {
if ( child.getKind() == Kind.ANNOTATION ) {
@@ -38,21 +39,22 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
level = Eclipse.createAnnotation(Getter.class, child).getInstance().value();
errorNode = child;
pos = child.get();
+ whineIfExists = true;
break;
}
}
}
- createGetterForField(level, fieldNode, errorNode, pos);
+ createGetterForField(level, fieldNode, errorNode, pos, whineIfExists);
}
@Override public boolean handle(AnnotationValues<Getter> annotation, Annotation ast, Node annotationNode) {
Node fieldNode = annotationNode.up();
AccessLevel level = annotation.getInstance().value();
- return createGetterForField(level, fieldNode, annotationNode, annotationNode.get());
+ return createGetterForField(level, fieldNode, annotationNode, annotationNode.get(), true);
}
- private boolean createGetterForField(AccessLevel level, Node fieldNode, Node errorNode, ASTNode pos) {
+ private boolean createGetterForField(AccessLevel level, Node fieldNode, Node errorNode, ASTNode pos, boolean whineIfExists) {
if ( fieldNode.getKind() != Kind.FIELD ) {
errorNode.addError("@Getter is only supported on a field.");
return false;
@@ -63,30 +65,40 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
String getterName = TransformationsUtil.toGetterName(
new String(field.name), nameEquals(fieldType.getTypeName(), "boolean"));
- TypeDeclaration parent = (TypeDeclaration) fieldNode.up().get();
- if ( parent.methods != null ) for ( AbstractMethodDeclaration method : parent.methods ) {
- if ( method.selector != null && new String(method.selector).equals(getterName) ) {
- errorNode.addWarning(String.format(
- "Not generating %s(): A method with that name already exists", getterName));
- return false;
- }
+ int modifier = toModifier(level) | (field.modifiers & ClassFileConstants.AccStatic);
+
+ switch ( methodExists(getterName, fieldNode) ) {
+ case EXISTS_BY_LOMBOK:
+ Node methodNode = getExistingLombokMethod(getterName, fieldNode);
+ injectScopeIntoGetter(modifier, field, (MethodDeclaration)methodNode.get(), (TypeDeclaration) methodNode.up().get());
+ return false;
+ case EXISTS_BY_USER:
+ if ( whineIfExists ) errorNode.addWarning(
+ String.format("Not generating %s(): A method with that name already exists", getterName));
+ return false;
+ default:
+ case NOT_EXISTS:
+ //continue with creating the getter
}
- int modifier = toModifier(level) | (field.modifiers & ClassFileConstants.AccStatic);
+ if ( new String(field.name).equals("a") ) fieldNode.up().traverse(new EclipseASTVisitor.Printer());
+ MethodDeclaration method = generateGetter((TypeDeclaration) fieldNode.up().get(), field, getterName, modifier, pos);
- MethodDeclaration method = generateGetter(parent, field, getterName, modifier, pos);
+ injectMethod(fieldNode.up(), method);
- if ( parent.methods == null ) {
- parent.methods = new AbstractMethodDeclaration[1];
- parent.methods[0] = method;
- } else {
- AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1];
- System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length);
- newArray[parent.methods.length] = method;
- parent.methods = newArray;
+ return false;
+ }
+
+ private void injectScopeIntoGetter(int modifier, FieldDeclaration field, MethodDeclaration method, TypeDeclaration parent) {
+ if ( parent.scope != null ) {
+ if ( method.binding != null ) {
+ method.binding.returnType = field.type.resolvedType;
+ } else {
+ method.scope = new MethodScope(parent.scope, method, false);
+ method.returnType.resolvedType = field.type.resolvedType;
+ method.binding = new MethodBinding(modifier, method.selector, method.returnType.resolvedType, null, null, parent.binding);
+ }
}
-
- return true;
}
private MethodDeclaration generateGetter(TypeDeclaration parent, FieldDeclaration field, String name,
@@ -100,8 +112,8 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
method.binding = null;
method.thrownExceptions = null;
method.typeParameters = null;
- method.scope = parent.scope == null ? null : new MethodScope(parent.scope, method, false);
- method.bits |= ASTNode.Bit24;
+ injectScopeIntoGetter(modifier, field, method, parent);
+ method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
Expression fieldExpression = new SingleNameReference(field.name, (field.declarationSourceStart << 32) | field.declarationSourceEnd);
Statement returnStatement = new ReturnStatement(fieldExpression, field.sourceStart, field.sourceEnd);
method.bodyStart = method.declarationSourceStart = method.sourceStart = pos.sourceStart;
diff --git a/src/lombok/eclipse/handlers/HandleSetter.java b/src/lombok/eclipse/handlers/HandleSetter.java
index d0d0d902..c5f87a93 100644
--- a/src/lombok/eclipse/handlers/HandleSetter.java
+++ b/src/lombok/eclipse/handlers/HandleSetter.java
@@ -1,9 +1,16 @@
package lombok.eclipse.handlers;
import static lombok.eclipse.handlers.PKG.*;
+import lombok.AccessLevel;
+import lombok.Setter;
+import lombok.core.AnnotationValues;
+import lombok.core.TransformationsUtil;
+import lombok.core.AST.Kind;
+import lombok.eclipse.Eclipse;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseAST.Node;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
@@ -16,24 +23,19 @@ import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.mangosdk.spi.ProviderFor;
-import lombok.AccessLevel;
-import lombok.Setter;
-import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
-import lombok.core.AST.Kind;
-import lombok.eclipse.Eclipse;
-import lombok.eclipse.EclipseAnnotationHandler;
-import lombok.eclipse.EclipseAST.Node;
-
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleSetter implements EclipseAnnotationHandler<Setter> {
public void generateSetterForField(Node fieldNode, ASTNode pos) {
- AccessLevel level = Setter.DEFAULT_ACCESS_LEVEL;
+ AccessLevel level = AccessLevel.PUBLIC;
Node errorNode = fieldNode;
+ boolean whineIfExists = false;
for ( Node child : fieldNode.down() ) {
if ( child.getKind() == Kind.ANNOTATION ) {
@@ -41,51 +43,68 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
level = Eclipse.createAnnotation(Setter.class, child).getInstance().value();
errorNode = child;
pos = child.get();
+ whineIfExists = true;
break;
}
}
}
- createSetterForField(level, fieldNode, errorNode, pos);
+ createSetterForField(level, fieldNode, errorNode, pos, whineIfExists);
}
@Override public boolean handle(AnnotationValues<Setter> annotation, Annotation ast, Node annotationNode) {
Node fieldNode = annotationNode.up();
if ( fieldNode.getKind() != Kind.FIELD ) return false;
AccessLevel level = annotation.getInstance().value();
- return createSetterForField(level, fieldNode, annotationNode, annotationNode.get());
+ return createSetterForField(level, fieldNode, annotationNode, annotationNode.get(), true);
}
- private boolean createSetterForField(AccessLevel level, Node fieldNode, Node errorNode, ASTNode pos) {
- if ( fieldNode.getKind() != Kind.FIELD ) return false;
+ private boolean createSetterForField(AccessLevel level, Node fieldNode, Node errorNode, ASTNode pos, boolean whineIfExists) {
+ if ( fieldNode.getKind() != Kind.FIELD ) {
+ errorNode.addError("@Setter is only supported on a field.");
+ return false;
+ }
+
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
String setterName = TransformationsUtil.toSetterName(new String(field.name));
- TypeDeclaration parent = (TypeDeclaration) fieldNode.up().get();
- if ( parent.methods != null ) for ( AbstractMethodDeclaration method : parent.methods ) {
- if ( method.selector != null && new String(method.selector).equals(setterName) ) {
- errorNode.addWarning(String.format(
- "Not generating %s(%s %s): A method with that name already exists",
- setterName, field.type, new String(field.name)));
- return false;
- }
+ int modifier = toModifier(level) | (field.modifiers & ClassFileConstants.AccStatic);
+
+ switch ( methodExists(setterName, fieldNode) ) {
+ case EXISTS_BY_LOMBOK:
+ Node methodNode = getExistingLombokMethod(setterName, fieldNode);
+ injectScopeIntoSetter(modifier, field, (MethodDeclaration)methodNode.get(), (TypeDeclaration) methodNode.up().get());
+ return false;
+ case EXISTS_BY_USER:
+ if ( whineIfExists ) errorNode.addWarning(
+ String.format("Not generating %s(%s %s): A method with that name already exists",
+ setterName, field.type, new String(field.name)));
+ return false;
+ default:
+ case NOT_EXISTS:
+ //continue with creating the setter
}
- int modifier = toModifier(level) | (field.modifiers & ClassFileConstants.AccStatic);
- MethodDeclaration method = generateSetter(parent, field, setterName, modifier, pos);
+ MethodDeclaration method = generateSetter((TypeDeclaration) fieldNode.up().get(), field, setterName, modifier, pos);
- if ( parent.methods == null ) {
- parent.methods = new AbstractMethodDeclaration[1];
- parent.methods[0] = method;
- } else {
- AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1];
- System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length);
- newArray[parent.methods.length] = method;
- parent.methods = newArray;
- }
+ injectMethod(fieldNode.up(), method);
- return true;
+ return false;
+ }
+
+ private void injectScopeIntoSetter(int modifier, FieldDeclaration field, MethodDeclaration method, TypeDeclaration parent) {
+ if ( parent.scope != null ) {
+ TypeBinding[] params = new TypeBinding[] { field.type.resolvedType };
+
+ if ( method.binding == null ) {
+ method.scope = new MethodScope(parent.scope, method, false);
+ method.binding = new MethodBinding(modifier, method.selector, BaseTypeBinding.VOID, params, null, parent.binding);
+ }
+ method.binding.parameters = params;
+ method.binding.returnType = BaseTypeBinding.VOID;
+ method.returnType.resolvedType = BaseTypeBinding.VOID;
+ }
}
private MethodDeclaration generateSetter(TypeDeclaration parent, FieldDeclaration field, String name,
@@ -102,7 +121,8 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
method.thrownExceptions = null;
method.typeParameters = null;
method.scope = parent.scope == null ? null : new MethodScope(parent.scope, method, false);
- method.bits |= ASTNode.Bit24;
+ method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ injectScopeIntoSetter(modifier, field, method, parent);
FieldReference thisX = new FieldReference(("this." + new String(field.name)).toCharArray(), pos);
thisX.receiver = new ThisReference(ast.sourceStart, ast.sourceEnd);
thisX.token = field.name;
diff --git a/src/lombok/eclipse/handlers/PKG.java b/src/lombok/eclipse/handlers/PKG.java
index 61f71140..d93807a7 100644
--- a/src/lombok/eclipse/handlers/PKG.java
+++ b/src/lombok/eclipse/handlers/PKG.java
@@ -3,6 +3,11 @@ package lombok.eclipse.handlers;
import java.lang.reflect.Modifier;
import lombok.AccessLevel;
+import lombok.core.AST.Kind;
+import lombok.eclipse.EclipseAST;
+
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
class PKG {
private PKG() {}
@@ -33,4 +38,63 @@ class PKG {
return string.contentEquals(sb);
}
+
+ enum MethodExistsResult {
+ NOT_EXISTS, EXISTS_BY_USER, EXISTS_BY_LOMBOK;
+ }
+
+ static MethodExistsResult methodExists(String methodName, EclipseAST.Node node) {
+ while ( node != null && !(node.get() instanceof TypeDeclaration) ) {
+ node = node.up();
+ }
+
+ if ( node.get() instanceof TypeDeclaration ) {
+ TypeDeclaration typeDecl = (TypeDeclaration)node.get();
+ if ( typeDecl.methods != null ) for ( AbstractMethodDeclaration def : typeDecl.methods ) {
+ char[] mName = ((AbstractMethodDeclaration)def).selector;
+ if ( mName == null ) continue;
+ if ( methodName.equals(new String(mName)) ) {
+ EclipseAST.Node existing = node.getNodeFor(def);
+ if ( existing == null || !existing.isHandled() ) return MethodExistsResult.EXISTS_BY_USER;
+ return MethodExistsResult.EXISTS_BY_LOMBOK;
+ }
+ }
+ }
+
+ return MethodExistsResult.NOT_EXISTS;
+ }
+
+ static EclipseAST.Node getExistingLombokMethod(String methodName, EclipseAST.Node node) {
+ while ( node != null && !(node.get() instanceof TypeDeclaration) ) {
+ node = node.up();
+ }
+
+ if ( node.get() instanceof TypeDeclaration ) {
+ for ( AbstractMethodDeclaration def : ((TypeDeclaration)node.get()).methods ) {
+ char[] mName = ((AbstractMethodDeclaration)def).selector;
+ if ( mName == null ) continue;
+ if ( methodName.equals(new String(mName)) ) {
+ EclipseAST.Node existing = node.getNodeFor(def);
+ if ( existing.isHandled() ) return existing;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ static void injectMethod(EclipseAST.Node type, AbstractMethodDeclaration method) {
+ TypeDeclaration parent = (TypeDeclaration) type.get();
+ if ( parent.methods == null ) {
+ parent.methods = new AbstractMethodDeclaration[1];
+ parent.methods[0] = method;
+ } else {
+ AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1];
+ System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length);
+ newArray[parent.methods.length] = method;
+ parent.methods = newArray;
+ }
+
+ type.add(method, Kind.METHOD).recursiveSetHandled();
+ }
}