diff options
-rw-r--r-- | src/lombok/Getter.java | 2 | ||||
-rw-r--r-- | src/lombok/Setter.java | 2 | ||||
-rw-r--r-- | src/lombok/core/AST.java | 19 | ||||
-rw-r--r-- | src/lombok/eclipse/Eclipse.java | 23 | ||||
-rw-r--r-- | src/lombok/eclipse/EclipseAST.java | 70 | ||||
-rw-r--r-- | src/lombok/eclipse/EclipseASTVisitor.java | 4 | ||||
-rw-r--r-- | src/lombok/eclipse/HandlerLibrary.java | 12 | ||||
-rw-r--r-- | src/lombok/eclipse/TransformEclipseAST.java | 11 | ||||
-rw-r--r-- | src/lombok/eclipse/handlers/HandleData.java | 127 | ||||
-rw-r--r-- | src/lombok/eclipse/handlers/HandleGetter.java | 66 | ||||
-rw-r--r-- | src/lombok/eclipse/handlers/HandleSetter.java | 92 | ||||
-rw-r--r-- | src/lombok/eclipse/handlers/PKG.java | 64 | ||||
-rw-r--r-- | src/lombok/javac/JavacAST.java | 30 | ||||
-rw-r--r-- | src/lombok/javac/handlers/HandleGetter.java | 23 | ||||
-rw-r--r-- | src/lombok/javac/handlers/HandleSetter.java | 25 | ||||
-rw-r--r-- | src/lombok/javac/handlers/PKG.java | 12 |
16 files changed, 450 insertions, 132 deletions
diff --git a/src/lombok/Getter.java b/src/lombok/Getter.java index 7510bf24..d59ea672 100644 --- a/src/lombok/Getter.java +++ b/src/lombok/Getter.java @@ -8,7 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Getter { - lombok.AccessLevel DEFAULT_ACCESS_LEVEL = lombok.AccessLevel.PUBLIC; - lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; } diff --git a/src/lombok/Setter.java b/src/lombok/Setter.java index acd1d180..b00d4158 100644 --- a/src/lombok/Setter.java +++ b/src/lombok/Setter.java @@ -8,7 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Setter { - lombok.AccessLevel DEFAULT_ACCESS_LEVEL = lombok.AccessLevel.PUBLIC; - lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; } diff --git a/src/lombok/core/AST.java b/src/lombok/core/AST.java index 2229f9ef..c1186d24 100644 --- a/src/lombok/core/AST.java +++ b/src/lombok/core/AST.java @@ -97,6 +97,10 @@ public abstract class AST<N> { protected abstract boolean calculateIsStructurallySignificant(); + public Node getNodeFor(N obj) { + return AST.this.get(obj); + } + public N get() { return node; } @@ -150,6 +154,19 @@ public abstract class AST<N> { return fileName; } + public Node add(N newChild, Kind kind) { + Node n = buildTree(newChild, kind); + if ( n == null ) return null; + n.parent = this; + return n; + } + + public Node recursiveSetHandled() { + this.handled = true; + for ( Node child : children ) child.recursiveSetHandled(); + return this; + } + public abstract void addError(String message); public abstract void addWarning(String message); @@ -164,6 +181,8 @@ public abstract class AST<N> { } } + protected abstract Node buildTree(N item, Kind kind); + protected static class FieldAccess { public final Field field; public final int dim; 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(); + } } diff --git a/src/lombok/javac/JavacAST.java b/src/lombok/javac/JavacAST.java index 7050df75..f0544256 100644 --- a/src/lombok/javac/JavacAST.java +++ b/src/lombok/javac/JavacAST.java @@ -94,6 +94,31 @@ public class JavacAST extends AST<JCTree> { return symtab; } + @Override protected Node buildTree(JCTree node, Kind kind) { + switch ( kind ) { + case COMPILATION_UNIT: + return buildCompilationUnit((JCCompilationUnit) node); + case TYPE: + return buildType((JCClassDecl) node); + case FIELD: + return buildField((JCVariableDecl) node); + case INITIALIZER: + return buildInitializer((JCBlock) node); + case METHOD: + return buildMethod((JCMethodDecl) node); + case ARGUMENT: + return buildLocalVar((JCVariableDecl) node, kind); + case LOCAL: + return buildLocalVar((JCVariableDecl) node, kind); + case STATEMENT: + return buildStatementOrExpression(node); + case ANNOTATION: + return buildAnnotation((JCAnnotation) node); + default: + throw new AssertionError("Did not expect: " + kind); + } + } + private Node buildCompilationUnit(JCCompilationUnit top) { List<Node> childNodes = new ArrayList<Node>(); for ( JCTree s : top.defs ) { @@ -310,6 +335,11 @@ public class JavacAST extends AST<JCTree> { } /** {@inheritDoc} */ + @Override public Node getNodeFor(JCTree obj) { + return (Node) super.getNodeFor(obj); + } + + /** {@inheritDoc} */ @Override public Node directUp() { return (Node) super.directUp(); } diff --git a/src/lombok/javac/handlers/HandleGetter.java b/src/lombok/javac/handlers/HandleGetter.java index 651bc018..3405810b 100644 --- a/src/lombok/javac/handlers/HandleGetter.java +++ b/src/lombok/javac/handlers/HandleGetter.java @@ -29,8 +29,9 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @ProviderFor(JavacAnnotationHandler.class) public class HandleGetter implements JavacAnnotationHandler<Getter> { public void generateGetterForField(Node fieldNode, DiagnosticPosition 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 JavacAnnotationHandler<Getter> { level = Javac.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, JCAnnotation 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, DiagnosticPosition pos) { + private boolean createGetterForField(AccessLevel level, Node fieldNode, Node errorNode, DiagnosticPosition pos, boolean whineIfExists) { if ( fieldNode.getKind() != Kind.FIELD ) { errorNode.addError("@Getter is only supported on a field."); return false; @@ -61,10 +63,16 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> { JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get(); String methodName = toGetterName(fieldDecl); - if ( methodExists(methodName, fieldNode) ) { - errorNode.addWarning( + switch ( methodExists(methodName, fieldNode) ) { + case EXISTS_BY_LOMBOK: + return true; + case EXISTS_BY_USER: + if ( whineIfExists ) errorNode.addWarning( String.format("Not generating %s(): A method with that name already exists", methodName)); return false; + default: + case NOT_EXISTS: + //continue with creating the getter } JCClassDecl javacClassTree = (JCClassDecl) fieldNode.up().get(); @@ -73,6 +81,9 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> { JCMethodDecl getterMethod = createGetter(access, fieldNode, fieldNode.getTreeMaker()); javacClassTree.defs = javacClassTree.defs.append(getterMethod); + + fieldNode.up().add(getterMethod, Kind.METHOD).recursiveSetHandled(); + return true; } diff --git a/src/lombok/javac/handlers/HandleSetter.java b/src/lombok/javac/handlers/HandleSetter.java index f1e73489..4999b5d8 100644 --- a/src/lombok/javac/handlers/HandleSetter.java +++ b/src/lombok/javac/handlers/HandleSetter.java @@ -31,8 +31,9 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @ProviderFor(JavacAnnotationHandler.class) public class HandleSetter implements JavacAnnotationHandler<Setter> { public void generateSetterForField(Node fieldNode, DiagnosticPosition 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 ) { @@ -40,21 +41,22 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> { level = Javac.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, JCAnnotation ast, Node annotationNode) { Node fieldNode = annotationNode.up(); 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, DiagnosticPosition pos) { + private boolean createSetterForField(AccessLevel level, Node fieldNode, Node errorNode, DiagnosticPosition pos, boolean whineIfExists) { if ( fieldNode.getKind() != Kind.FIELD ) { fieldNode.addError("@Setter is only supported on a field."); return false; @@ -63,11 +65,17 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> { JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get(); String methodName = toSetterName(fieldDecl); - if ( methodExists(methodName, fieldNode) ) { - errorNode.addWarning( + switch ( methodExists(methodName, fieldNode) ) { + case EXISTS_BY_LOMBOK: + return true; + case EXISTS_BY_USER: + if ( whineIfExists ) errorNode.addWarning( String.format("Not generating %s(%s %s): A method with that name already exists", - methodName, fieldDecl.vartype, fieldDecl.name)); + methodName, fieldDecl.vartype, fieldDecl.name)); return false; + default: + case NOT_EXISTS: + //continue with creating the setter } JCClassDecl javacClassTree = (JCClassDecl) fieldNode.up().get(); @@ -76,6 +84,9 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> { JCMethodDecl setterMethod = createSetter(access, fieldNode, fieldNode.getTreeMaker()); javacClassTree.defs = javacClassTree.defs.append(setterMethod); + + fieldNode.up().add(setterMethod, Kind.METHOD).recursiveSetHandled(); + return true; } diff --git a/src/lombok/javac/handlers/PKG.java b/src/lombok/javac/handlers/PKG.java index 2c038b2d..138559a9 100644 --- a/src/lombok/javac/handlers/PKG.java +++ b/src/lombok/javac/handlers/PKG.java @@ -28,7 +28,11 @@ class PKG { return TransformationsUtil.toSetterName(fieldName); } - static boolean methodExists(String methodName, JavacAST.Node node) { + enum MethodExistsResult { + NOT_EXISTS, EXISTS_BY_USER, EXISTS_BY_LOMBOK; + } + + static MethodExistsResult methodExists(String methodName, JavacAST.Node node) { while ( node != null && !(node.get() instanceof JCClassDecl) ) { node = node.up(); } @@ -37,13 +41,15 @@ class PKG { for ( JCTree def : ((JCClassDecl)node.get()).defs ) { if ( def instanceof JCMethodDecl ) { if ( ((JCMethodDecl)def).name.contentEquals(methodName) ) { - return true; + JavacAST.Node existing = node.getNodeFor(def); + if ( existing == null || !existing.isHandled() ) return MethodExistsResult.EXISTS_BY_USER; + return MethodExistsResult.EXISTS_BY_LOMBOK; } } } } - return false; + return MethodExistsResult.NOT_EXISTS; } static int toJavacModifier(AccessLevel accessLevel) { |