diff options
author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2010-11-09 20:37:25 +0100 |
---|---|---|
committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2010-11-09 20:37:25 +0100 |
commit | 46d471e9c3dc32b03c34804df1819739a4dffc50 (patch) | |
tree | 9c31d75426bf8fdb1943bef2a996485640f7bf5e /src/core/lombok/eclipse | |
parent | 92b7efac48c18f22b81098cf1d844a891bb71648 (diff) | |
parent | 98d8a9f63b3183005174abb7691a1692347b9a2e (diff) | |
download | lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.tar.gz lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.tar.bz2 lombok-46d471e9c3dc32b03c34804df1819739a4dffc50.zip |
Merge branch 'master' into annoGetSet
Diffstat (limited to 'src/core/lombok/eclipse')
-rw-r--r-- | src/core/lombok/eclipse/Eclipse.java | 193 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java | 60 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleCleanup.java | 28 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java | 202 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleLog.java | 284 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleSynchronized.java | 2 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleVal.java | 61 |
7 files changed, 746 insertions, 84 deletions
diff --git a/src/core/lombok/eclipse/Eclipse.java b/src/core/lombok/eclipse/Eclipse.java index c70660f4..f5b80552 100644 --- a/src/core/lombok/eclipse/Eclipse.java +++ b/src/core/lombok/eclipse/Eclipse.java @@ -25,10 +25,12 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; import lombok.core.AnnotationValues; import lombok.core.TypeLibrary; @@ -62,7 +64,13 @@ import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; +import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; import org.osgi.framework.Bundle; public class Eclipse { @@ -156,7 +164,6 @@ public class Eclipse { return result; } - /** * You can't share TypeParameter objects or bad things happen; for example, one 'T' resolves differently * from another 'T', even for the same T in a single class file. Unfortunately the TypeParameter type hierarchy @@ -292,6 +299,159 @@ public class Eclipse { return ref; } + private static long pos(ASTNode node) { + return ((long) node.sourceStart << 32) | (node.sourceEnd & 0xFFFFFFFFL); + } + + public static long[] poss(ASTNode node, int repeat) { + long p = ((long) node.sourceStart << 32) | (node.sourceEnd & 0xFFFFFFFFL); + long[] out = new long[repeat]; + Arrays.fill(out, p); + return out; + } + + public static TypeReference makeType(TypeBinding binding, ASTNode pos, boolean allowCompound) { + int dims = binding.dimensions(); + binding = binding.leafComponentType(); + + // Primitives + + char[] base = null; + + switch (binding.id) { + case TypeIds.T_int: + base = TypeConstants.INT; + break; + case TypeIds.T_long: + base = TypeConstants.LONG; + break; + case TypeIds.T_short: + base = TypeConstants.SHORT; + break; + case TypeIds.T_byte: + base = TypeConstants.BYTE; + break; + case TypeIds.T_double: + base = TypeConstants.DOUBLE; + break; + case TypeIds.T_float: + base = TypeConstants.FLOAT; + break; + case TypeIds.T_boolean: + base = TypeConstants.BOOLEAN; + break; + case TypeIds.T_char: + base = TypeConstants.CHAR; + break; + case TypeIds.T_void: + base = TypeConstants.VOID; + break; + case TypeIds.T_null: + return null; + } + + if (base != null) { + if (dims > 0) { + return new ArrayTypeReference(base, dims, pos(pos)); + } + return new SingleTypeReference(base, pos(pos)); + } + + if (binding.isAnonymousType()) { + ReferenceBinding ref = (ReferenceBinding)binding; + ReferenceBinding[] supers = ref.superInterfaces(); + if (supers == null || supers.length == 0) supers = new ReferenceBinding[] {ref.superclass()}; + if (supers[0] == null) return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3)); + return makeType(supers[0], pos, false); + } + + if (binding instanceof CaptureBinding) { + return makeType(((CaptureBinding)binding).wildcard, pos, allowCompound); + } + + if (binding.isUnboundWildcard()) { + if (!allowCompound) { + return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3)); + } else { + Wildcard out = new Wildcard(Wildcard.UNBOUND); + out.sourceStart = pos.sourceStart; + out.sourceEnd = pos.sourceEnd; + return out; + } + } + + if (binding.isWildcard()) { + WildcardBinding wildcard = (WildcardBinding) binding; + if (wildcard.boundKind == Wildcard.EXTENDS) { + if (!allowCompound) { + return makeType(wildcard.bound, pos, false); + } else { + Wildcard out = new Wildcard(Wildcard.EXTENDS); + out.bound = makeType(wildcard.bound, pos, false); + out.sourceStart = pos.sourceStart; + out.sourceEnd = pos.sourceEnd; + return out; + } + } else if (allowCompound && wildcard.boundKind == Wildcard.SUPER) { + Wildcard out = new Wildcard(Wildcard.SUPER); + out.bound = makeType(wildcard.bound, pos, false); + out.sourceStart = pos.sourceStart; + out.sourceEnd = pos.sourceEnd; + return out; + } else { + return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3)); + } + } + + char[][] parts; + + if (binding.isLocalType() || binding.isTypeVariable()) { + parts = new char[][] { binding.shortReadableName() }; + } else { + String[] pkg = new String(binding.qualifiedPackageName()).split("\\."); + String[] name = new String(binding.qualifiedSourceName()).split("\\."); + if (pkg.length == 1 && pkg[0].isEmpty()) pkg = new String[0]; + parts = new char[pkg.length + name.length][]; + int ptr; + for (ptr = 0; ptr < pkg.length; ptr++) parts[ptr] = pkg[ptr].toCharArray(); + for (; ptr < pkg.length + name.length; ptr++) parts[ptr] = name[ptr - pkg.length].toCharArray(); + } + + TypeReference[] params = new TypeReference[0]; + + if (binding instanceof ParameterizedTypeBinding) { + ParameterizedTypeBinding paramized = (ParameterizedTypeBinding) binding; + if (paramized.arguments != null) { + params = new TypeReference[paramized.arguments.length]; + for (int i = 0; i < params.length; i++) { + params[i] = makeType(paramized.arguments[i], pos, true); + } + } + } + + if (params.length > 0) { + if (parts.length > 1) { + TypeReference[][] typeArguments = new TypeReference[parts.length][]; + typeArguments[typeArguments.length - 1] = params; + return new ParameterizedQualifiedTypeReference(parts, typeArguments, dims, poss(pos, parts.length)); + } + return new ParameterizedSingleTypeReference(parts[0], params, dims, pos(pos)); + } + + if (dims > 0) { + if (parts.length > 1) { + return new ArrayQualifiedTypeReference(parts, dims, poss(pos, parts.length)); + } + return new ArrayTypeReference(parts[0], dims, pos(pos)); + } + + if (parts.length > 1) { + return new QualifiedTypeReference(parts, poss(pos, parts.length)); + } + return new SingleTypeReference(parts[0], pos(pos)); + + } + public static Annotation[] copyAnnotations(Annotation[] annotations, ASTNode source) { return copyAnnotations(annotations, null, source); } @@ -377,6 +537,7 @@ public class Eclipse { if (!Modifier.isPublic(m.getModifiers())) continue; String name = m.getName(); List<String> raws = new ArrayList<String>(); + List<Object> expressionValues = new ArrayList<Object>(); List<Object> guesses = new ArrayList<Object>(); Expression fullExpression = null; Expression[] expressions = null; @@ -397,6 +558,7 @@ public class Eclipse { StringBuffer sb = new StringBuffer(); ex.print(0, sb); raws.add(sb.toString()); + expressionValues.add(ex); guesses.add(calculateValue(ex)); } } @@ -404,7 +566,7 @@ public class Eclipse { final Expression fullExpr = fullExpression; final Expression[] exprs = expressions; - values.put(name, new AnnotationValue(annotationNode, raws, guesses, isExplicit) { + values.put(name, new AnnotationValue(annotationNode, raws, expressionValues, guesses, isExplicit) { @Override public void setError(String message, int valueIdx) { Expression ex; if (valueIdx == -1) ex = fullExpr; @@ -474,12 +636,16 @@ public class Eclipse { } } + private static Map<ASTNode, ASTNode> generatedNodes = new WeakHashMap<ASTNode, ASTNode>(); + public static ASTNode getGeneratedBy(ASTNode node) { - try { - return (ASTNode) generatedByField.get(node); - } catch (Exception t) { - //ignore - no $generatedBy exists when running in ecj. - return null; + if (generatedByField != null) { + try { + return (ASTNode) generatedByField.get(node); + } catch (Exception e) {} + } + synchronized (generatedNodes) { + return generatedNodes.get(node); } } @@ -488,12 +654,15 @@ public class Eclipse { } public static ASTNode setGeneratedBy(ASTNode node, ASTNode source) { - try { - generatedByField.set(node, source); - } catch (Exception t) { - //ignore - no $generatedBy exists when running in ecj. + if (generatedByField != null) { + try { + generatedByField.set(node, source); + return node; + } catch (Exception e) {} + } + synchronized (generatedNodes) { + generatedNodes.put(node, source); } - return node; } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 5005752b..019ae637 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -23,6 +23,7 @@ package lombok.eclipse.handlers; import static lombok.eclipse.Eclipse.*; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -42,6 +43,7 @@ import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.Clinit; import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; @@ -406,9 +408,17 @@ public class EclipseHandlerUtil { /** * Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}. + * The field carries the @{@link SuppressWarnings}("all") annotation. */ - public static void injectField(EclipseNode type, FieldDeclaration field) { + public static void injectFieldSuppressWarnings(EclipseNode type, FieldDeclaration field) { field.annotations = createSuppressWarningsAll(field, field.annotations); + 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) { TypeDeclaration parent = (TypeDeclaration) type.get(); if (parent.fields == null) { @@ -421,9 +431,24 @@ public class EclipseHandlerUtil { parent.fields = newArray; } + if ((field.modifiers & Modifier.STATIC) != 0) { + if (!hasClinit(parent)) { + parent.addClinit(); + } + } + type.add(field, Kind.FIELD).recursiveSetHandled(); } + private static boolean hasClinit(TypeDeclaration parent) { + if (parent.methods == null) return false; + + for (AbstractMethodDeclaration method : parent.methods) { + if (method instanceof Clinit) return true; + } + return false; + } + /** * Inserts a method into an existing type. The type must represent a {@code TypeDeclaration}. */ @@ -435,25 +460,42 @@ public class EclipseHandlerUtil { parent.methods = new AbstractMethodDeclaration[1]; parent.methods[0] = method; } else { - boolean injectionComplete = false; if (method instanceof ConstructorDeclaration) { for (int i = 0 ; i < parent.methods.length ; i++) { if (parent.methods[i] instanceof ConstructorDeclaration && (parent.methods[i].bits & ASTNode.IsDefaultConstructor) != 0) { EclipseNode tossMe = type.getNodeFor(parent.methods[i]); - parent.methods[i] = method; + + AbstractMethodDeclaration[] withoutGeneratedConstructor = new AbstractMethodDeclaration[parent.methods.length - 1]; + + System.arraycopy(parent.methods, 0, withoutGeneratedConstructor, 0, i); + System.arraycopy(parent.methods, i + 1, withoutGeneratedConstructor, i, parent.methods.length - i - 1); + + parent.methods = withoutGeneratedConstructor; if (tossMe != null) tossMe.up().removeChild(tossMe); - injectionComplete = true; break; } } } - if (!injectionComplete) { - 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; + int insertionPoint; + for (insertionPoint = 0; insertionPoint < parent.methods.length; insertionPoint++) { + AbstractMethodDeclaration current = parent.methods[insertionPoint]; + if (current instanceof Clinit) continue; + if (method instanceof ConstructorDeclaration) { + if (current instanceof ConstructorDeclaration) continue; + break; + } + if (Eclipse.isGenerated(current)) continue; + break; + } + AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1]; + System.arraycopy(parent.methods, 0, newArray, 0, insertionPoint); + if (insertionPoint <= parent.methods.length) { + System.arraycopy(parent.methods, insertionPoint, newArray, insertionPoint + 1, parent.methods.length - insertionPoint); } + + newArray[insertionPoint] = method; + parent.methods = newArray; } type.add(method, Kind.METHOD).recursiveSetHandled(); diff --git a/src/core/lombok/eclipse/handlers/HandleCleanup.java b/src/core/lombok/eclipse/handlers/HandleCleanup.java index d296e96b..33ab7fb9 100644 --- a/src/core/lombok/eclipse/handlers/HandleCleanup.java +++ b/src/core/lombok/eclipse/handlers/HandleCleanup.java @@ -37,9 +37,13 @@ import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.CaseStatement; import org.eclipse.jdt.internal.compiler.ast.CastExpression; +import org.eclipse.jdt.internal.compiler.ast.EqualExpression; +import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; @@ -157,7 +161,29 @@ public class HandleCleanup implements EclipseAnnotationHandler<Cleanup> { } unsafeClose.nameSourcePosition = nameSourcePosition; unsafeClose.selector = cleanupName.toCharArray(); - finallyBlock[0] = unsafeClose; + + + int pS = ast.sourceStart, pE = ast.sourceEnd; + long p = (long)pS << 32 | pE; + + SingleNameReference varName = new SingleNameReference(decl.name, p); + Eclipse.setGeneratedBy(varName, ast); + NullLiteral nullLiteral = new NullLiteral(pS, pE); + Eclipse.setGeneratedBy(nullLiteral, ast); + EqualExpression equalExpression = new EqualExpression(varName, nullLiteral, OperatorIds.NOT_EQUAL); + equalExpression.sourceStart = pS; equalExpression.sourceEnd = pE; + Eclipse.setGeneratedBy(equalExpression, ast); + + Block closeBlock = new Block(0); + closeBlock.statements = new Statement[1]; + closeBlock.statements[0] = unsafeClose; + Eclipse.setGeneratedBy(closeBlock, ast); + IfStatement ifStatement = new IfStatement(equalExpression, closeBlock, 0, 0); + Eclipse.setGeneratedBy(ifStatement, ast); + + + + finallyBlock[0] = ifStatement; tryStatement.finallyBlock = new Block(0); Eclipse.setGeneratedBy(tryStatement.finallyBlock, ast); tryStatement.finallyBlock.statements = finallyBlock; diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index e501c3f1..ed13fd1b 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -47,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FalseLiteral; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.IfStatement; +import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; @@ -202,9 +203,13 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA } } + boolean needsCanEqual = false; switch (methodExists("equals", typeNode)) { case NOT_EXISTS: - MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly); + boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0; + needsCanEqual = !isDirectDescendantOfObject || !isFinal; + + MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly, needsCanEqual); injectMethod(typeNode, equals); break; case EXISTS_BY_LOMBOK: @@ -217,6 +222,19 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA break; } + if (needsCanEqual) { + switch (methodExists("canEqual", typeNode)) { + case NOT_EXISTS: + MethodDeclaration equals = createCanEqual(typeNode, errorNode.get()); + injectMethod(typeNode, equals); + break; + case EXISTS_BY_LOMBOK: + case EXISTS_BY_USER: + default: + break; + } + } + switch (methodExists("hashCode", typeNode)) { case NOT_EXISTS: MethodDeclaration hashCode = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly); @@ -415,9 +433,10 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA return method; } - private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly) { + private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly, boolean needsCanEqual) { int pS = source.sourceStart; int pE = source.sourceEnd; long p = (long)pS << 32 | pE; + TypeDeclaration typeDecl = (TypeDeclaration)type.get(); MethodDeclaration method = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); @@ -458,75 +477,36 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA statements.add(ifOtherEqualsThis); } - /* if (o == null) return false; */ { + /* if (!(o instanceof MyType) return false; */ { SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); Eclipse.setGeneratedBy(oRef, source); - NullLiteral nullLiteral = new NullLiteral(pS, pE); - Eclipse.setGeneratedBy(nullLiteral, source); - EqualExpression otherEqualsNull = new EqualExpression(oRef, nullLiteral, OperatorIds.EQUAL_EQUAL); - Eclipse.setGeneratedBy(otherEqualsNull, source); + + SingleTypeReference typeReference = new SingleTypeReference(typeDecl.name, p); + Eclipse.setGeneratedBy(typeReference, source); + + InstanceOfExpression instanceOf = new InstanceOfExpression(oRef, typeReference); + instanceOf.sourceStart = pS; instanceOf.sourceEnd = pE; + Eclipse.setGeneratedBy(instanceOf, source); + + Expression notInstanceOf = new UnaryExpression(instanceOf, OperatorIds.NOT); + Eclipse.setGeneratedBy(notInstanceOf, source); FalseLiteral falseLiteral = new FalseLiteral(pS, pE); Eclipse.setGeneratedBy(falseLiteral, source); + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifOtherEqualsNull = new IfStatement(otherEqualsNull, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifOtherEqualsNull, source); - statements.add(ifOtherEqualsNull); - } - - /* if (o.getClass() != getClass()) return false; */ { - MessageSend otherGetClass = new MessageSend(); - otherGetClass.sourceStart = pS; otherGetClass.sourceEnd = pE; - Eclipse.setGeneratedBy(otherGetClass, source); - otherGetClass.receiver = new SingleNameReference(new char[] { 'o' }, p); - Eclipse.setGeneratedBy(otherGetClass.receiver, source); - otherGetClass.selector = "getClass".toCharArray(); - MessageSend thisGetClass = new MessageSend(); - thisGetClass.sourceStart = pS; thisGetClass.sourceEnd = pE; - Eclipse.setGeneratedBy(thisGetClass, source); - thisGetClass.receiver = new ThisReference(pS, pE); - Eclipse.setGeneratedBy(thisGetClass.receiver, source); - thisGetClass.selector = "getClass".toCharArray(); - EqualExpression classesNotEqual = new EqualExpression(otherGetClass, thisGetClass, OperatorIds.NOT_EQUAL); - Eclipse.setGeneratedBy(classesNotEqual, source); - FalseLiteral falseLiteral = new FalseLiteral(pS, pE); - Eclipse.setGeneratedBy(falseLiteral, source); - ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); - Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifClassesNotEqual = new IfStatement(classesNotEqual, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifClassesNotEqual, source); - statements.add(ifClassesNotEqual); + + IfStatement ifNotInstanceOf = new IfStatement(notInstanceOf, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifNotInstanceOf, source); + statements.add(ifNotInstanceOf); } - char[] otherN = "other".toCharArray(); - - /* if (!super.equals(o)) return false; */ - if (callSuper) { - MessageSend callToSuper = new MessageSend(); - callToSuper.sourceStart = pS; callToSuper.sourceEnd = pE; - Eclipse.setGeneratedBy(callToSuper, source); - callToSuper.receiver = new SuperReference(pS, pE); - Eclipse.setGeneratedBy(callToSuper.receiver, source); - callToSuper.selector = "equals".toCharArray(); - SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); - Eclipse.setGeneratedBy(oRef, source); - callToSuper.arguments = new Expression[] {oRef}; - Expression superNotEqual = new UnaryExpression(callToSuper, OperatorIds.NOT); - Eclipse.setGeneratedBy(superNotEqual, source); - FalseLiteral falseLiteral = new FalseLiteral(pS, pE); - Eclipse.setGeneratedBy(falseLiteral, source); - ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); - Eclipse.setGeneratedBy(returnFalse, source); - IfStatement ifSuperEquals = new IfStatement(superNotEqual, returnFalse, pS, pE); - Eclipse.setGeneratedBy(ifSuperEquals, source); - statements.add(ifSuperEquals); - } + char[] otherName = "other".toCharArray(); - TypeDeclaration typeDecl = (TypeDeclaration)type.get(); /* MyType<?> other = (MyType<?>) o; */ { if (!fields.isEmpty()) { - LocalDeclaration other = new LocalDeclaration(otherN, pS, pE); + LocalDeclaration other = new LocalDeclaration(otherName, pS, pE); other.modifiers |= ClassFileConstants.AccFinal; Eclipse.setGeneratedBy(other, source); char[] typeName = typeDecl.name; @@ -556,11 +536,63 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA } } + /* if (!other.canEqual(this)) return false; */ { + if (needsCanEqual) { + MessageSend otherCanEqual = new MessageSend(); + otherCanEqual.sourceStart = pS; otherCanEqual.sourceEnd = pE; + Eclipse.setGeneratedBy(otherCanEqual, source); + otherCanEqual.receiver = new SingleNameReference(otherName, p); + Eclipse.setGeneratedBy(otherCanEqual.receiver, source); + otherCanEqual.selector = "canEqual".toCharArray(); + + ThisReference thisReference = new ThisReference(pS, pE); + Eclipse.setGeneratedBy(thisReference, source); + + otherCanEqual.arguments = new Expression[] {thisReference}; + + Expression notOtherCanEqual = new UnaryExpression(otherCanEqual, OperatorIds.NOT); + Eclipse.setGeneratedBy(notOtherCanEqual, source); + + FalseLiteral falseLiteral = new FalseLiteral(pS, pE); + Eclipse.setGeneratedBy(falseLiteral, source); + + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); + Eclipse.setGeneratedBy(returnFalse, source); + + IfStatement ifNotCanEqual = new IfStatement(notOtherCanEqual, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifNotCanEqual, source); + + statements.add(ifNotCanEqual); + } + } + + /* if (!super.equals(o)) return false; */ + if (callSuper) { + MessageSend callToSuper = new MessageSend(); + callToSuper.sourceStart = pS; callToSuper.sourceEnd = pE; + Eclipse.setGeneratedBy(callToSuper, source); + callToSuper.receiver = new SuperReference(pS, pE); + Eclipse.setGeneratedBy(callToSuper.receiver, source); + callToSuper.selector = "equals".toCharArray(); + SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); + Eclipse.setGeneratedBy(oRef, source); + callToSuper.arguments = new Expression[] {oRef}; + Expression superNotEqual = new UnaryExpression(callToSuper, OperatorIds.NOT); + Eclipse.setGeneratedBy(superNotEqual, source); + FalseLiteral falseLiteral = new FalseLiteral(pS, pE); + Eclipse.setGeneratedBy(falseLiteral, source); + ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE); + Eclipse.setGeneratedBy(returnFalse, source); + IfStatement ifSuperEquals = new IfStatement(superNotEqual, returnFalse, pS, pE); + Eclipse.setGeneratedBy(ifSuperEquals, source); + statements.add(ifSuperEquals); + } + for (EclipseNode field : fields) { TypeReference fType = getFieldType(field, useFieldsDirectly); char[] token = fType.getLastToken(); Expression thisFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source); - Expression otherFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source, otherN); + Expression otherFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source, otherName); if (fType.dimensions() == 0 && token != null) { if (Arrays.equals(TypeConstants.FLOAT, token)) { @@ -589,7 +621,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA Eclipse.setGeneratedBy(equalsCall, source); equalsCall.receiver = createFieldAccessor(field, useFieldsDirectly, source); equalsCall.selector = "equals".toCharArray(); - equalsCall.arguments = new Expression[] { createFieldAccessor(field, useFieldsDirectly, source, otherN) }; + equalsCall.arguments = new Expression[] { createFieldAccessor(field, useFieldsDirectly, source, otherName) }; UnaryExpression fieldsNotEqual = new UnaryExpression(equalsCall, OperatorIds.NOT); fieldsNotEqual.sourceStart = pS; fieldsNotEqual.sourceEnd = pE; Eclipse.setGeneratedBy(fieldsNotEqual, source); @@ -639,6 +671,54 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA return method; } + + private MethodDeclaration createCanEqual(EclipseNode type, ASTNode source) { + /* public boolean canEquals(final java.lang.Object other) { + * return other instanceof MyType; + * } + */ + int pS = source.sourceStart; int pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + char[] otherName = "other".toCharArray(); + + MethodDeclaration method = new MethodDeclaration( + ((CompilationUnitDeclaration) type.top().get()).compilationResult); + Eclipse.setGeneratedBy(method, source); + method.modifiers = EclipseHandlerUtil.toEclipseModifier(AccessLevel.PUBLIC); + method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); + method.returnType.sourceStart = pS; method.returnType.sourceEnd = pE; + Eclipse.setGeneratedBy(method.returnType, source); + method.selector = "canEqual".toCharArray(); + method.thrownExceptions = null; + method.typeParameters = null; + method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart; + method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd; + TypeReference objectRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { p, p, p }); + Eclipse.setGeneratedBy(objectRef, source); + method.arguments = new Argument[] {new Argument(otherName, 0, objectRef, Modifier.FINAL)}; + method.arguments[0].sourceStart = pS; method.arguments[0].sourceEnd = pE; + Eclipse.setGeneratedBy(method.arguments[0], source); + + SingleNameReference otherRef = new SingleNameReference(otherName, p); + Eclipse.setGeneratedBy(otherRef, source); + + SingleTypeReference typeReference = new SingleTypeReference(((TypeDeclaration)type.get()).name, p); + Eclipse.setGeneratedBy(typeReference, source); + + InstanceOfExpression instanceOf = new InstanceOfExpression(otherRef, typeReference); + instanceOf.sourceStart = pS; instanceOf.sourceEnd = pE; + Eclipse.setGeneratedBy(instanceOf, source); + + ReturnStatement returnStatement = new ReturnStatement(instanceOf, pS, pE); + Eclipse.setGeneratedBy(returnStatement, source); + + method.statements = new Statement[] {returnStatement}; + return method; + } + + private IfStatement generateCompareFloatOrDouble(Expression thisRef, Expression otherRef, char[] floatOrDouble, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; /* if (Float.compare(fieldName, other.fieldName) != 0) return false */ diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java new file mode 100644 index 00000000..736e6e43 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -0,0 +1,284 @@ +/* + * Copyright © 2009 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.fromQualifiedName; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.lang.reflect.Modifier; +import java.util.Arrays; + +import lombok.core.AnnotationValues; +import lombok.eclipse.Eclipse; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; + +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; +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.NameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +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.mangosdk.spi.ProviderFor; + +public class HandleLog { + + private HandleLog() { + throw new UnsupportedOperationException(); + } + + public static boolean processAnnotation(LoggingFramework framework, AnnotationValues<? extends java.lang.annotation.Annotation> annotation, Annotation source, EclipseNode annotationNode) { + Expression annotationValue = (Expression) annotation.getActualExpression("value"); + if (annotationValue != null && !(annotationValue instanceof ClassLiteralAccess)) { + return true; + } + ClassLiteralAccess loggingType = (ClassLiteralAccess)annotationValue; + + EclipseNode owner = annotationNode.up(); + switch (owner.getKind()) { + case TYPE: + TypeDeclaration typeDecl = null; + if (owner.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) owner.get(); + int modifiers = typeDecl == null ? 0 : typeDecl.modifiers; + + boolean notAClass = (modifiers & + (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; + + if (typeDecl == null || notAClass) { + annotationNode.addError("@Log is legal only on classes and enums."); + return false; + } + + if (fieldExists("log", owner) != MemberExistsResult.NOT_EXISTS) { + annotationNode.addWarning("Field 'log' already exists."); + return true; + } + + if (loggingType == null) { + loggingType = selfType(owner, source); + } + + injectField(owner, createField(framework, source, loggingType)); + owner.rebuild(); + return true; + default: + annotationNode.addError("@Log is legal only on types."); + return true; + } + } + + private static ClassLiteralAccess selfType(EclipseNode type, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + TypeDeclaration typeDeclaration = (TypeDeclaration)type.get(); + TypeReference typeReference = new SingleTypeReference(typeDeclaration.name, p); + Eclipse.setGeneratedBy(typeReference, source); + + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, typeReference); + Eclipse.setGeneratedBy(result, source); + + return result; + } + + private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + // private static final <loggerType> log = <factoryMethod>(<parameter>); + + FieldDeclaration fieldDecl = new FieldDeclaration("log".toCharArray(), 0, -1); + Eclipse.setGeneratedBy(fieldDecl, source); + fieldDecl.declarationSourceEnd = -1; + fieldDecl.modifiers = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; + + fieldDecl.type = createTypeReference(framework.getLoggerTypeName(), source); + + MessageSend factoryMethodCall = new MessageSend(); + Eclipse.setGeneratedBy(factoryMethodCall, source); + + factoryMethodCall.receiver = createNameReference(framework.getLoggerFactoryTypeName(), source); + factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray(); + + Expression parameter = framework.createFactoryParameter(loggingType, source); + + factoryMethodCall.arguments = new Expression[] { parameter }; + factoryMethodCall.nameSourcePosition = p; + factoryMethodCall.sourceStart = pS; + factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE; + + fieldDecl.initialization = factoryMethodCall; + + return fieldDecl; + } + + private static TypeReference createTypeReference(String typeName, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + TypeReference typeReference; + if (typeName.contains(".")) { + + char[][] typeNameTokens = fromQualifiedName(typeName); + long[] pos = new long[typeNameTokens.length]; + Arrays.fill(pos, p); + + typeReference = new QualifiedTypeReference(typeNameTokens, pos); + } + else { + typeReference = null; + } + + Eclipse.setGeneratedBy(typeReference, source); + return typeReference; + } + + private static NameReference createNameReference(String name, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + char[][] nameTokens = fromQualifiedName(name); + long[] pos = new long[nameTokens.length]; + Arrays.fill(pos, p); + + QualifiedNameReference nameReference = new QualifiedNameReference(nameTokens, pos, pS, pE); + nameReference.statementEnd = pE; + + Eclipse.setGeneratedBy(nameReference, source); + return nameReference; + } + + /** + * Handles the {@link lombok.extern.apachecommons.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleCommonsLog implements EclipseAnnotationHandler<lombok.extern.apachecommons.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.apachecommons.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.jul.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleJulLog implements EclipseAnnotationHandler<lombok.extern.jul.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.jul.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.log4j.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleLog4jLog implements EclipseAnnotationHandler<lombok.extern.log4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.log4j.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode); + } + } + + /** + * Handles the {@link lombok.extern.slf4j.Log} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleSlf4jLog implements EclipseAnnotationHandler<lombok.extern.slf4j.Log> { + @Override public boolean handle(AnnotationValues<lombok.extern.slf4j.Log> annotation, Annotation source, EclipseNode annotationNode) { + return processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode); + } + } + + enum LoggingFramework { + // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); + COMMONS(lombok.extern.jul.Log.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory", "getLog"), + + // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); + JUL(lombok.extern.jul.Log.class, "java.util.logging.Logger", "java.util.logging.Logger", "getLogger") { + @Override public Expression createFactoryParameter(ClassLiteralAccess type, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + MessageSend factoryParameterCall = new MessageSend(); + Eclipse.setGeneratedBy(factoryParameterCall, source); + + factoryParameterCall.receiver = super.createFactoryParameter(type, source); + factoryParameterCall.selector = "getName".toCharArray(); + + factoryParameterCall.nameSourcePosition = p; + factoryParameterCall.sourceStart = pS; + factoryParameterCall.sourceEnd = factoryParameterCall.statementEnd = pE; + + return factoryParameterCall; + } + }, + + // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); + LOG4J(lombok.extern.jul.Log.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger", "getLogger"), + + // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); + SLF4J(lombok.extern.slf4j.Log.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory", "getLogger"), + + ; + + private final Class<? extends java.lang.annotation.Annotation> annotationClass; + private final String loggerTypeName; + private final String loggerFactoryTypeName; + private final String loggerFactoryMethodName; + + LoggingFramework(Class<? extends java.lang.annotation.Annotation> annotationClass, String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName) { + this.annotationClass = annotationClass; + this.loggerTypeName = loggerTypeName; + this.loggerFactoryTypeName = loggerFactoryTypeName; + this.loggerFactoryMethodName = loggerFactoryMethodName; + } + + final Class<? extends java.lang.annotation.Annotation> getAnnotationClass() { + return annotationClass; + } + + final String getLoggerTypeName() { + return loggerTypeName; + } + + final String getLoggerFactoryTypeName() { + return loggerFactoryTypeName; + } + + final String getLoggerFactoryMethodName() { + return loggerFactoryMethodName; + } + + Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source){ + TypeReference copy = Eclipse.copyType(loggingType.type, source); + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy); + Eclipse.setGeneratedBy(result, source); + return result; + }; + } +} diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index fde36192..b77099b5 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -101,7 +101,7 @@ public class HandleSynchronized implements EclipseAnnotationHandler<Synchronized fieldDecl.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { 0, 0, 0 }); Eclipse.setGeneratedBy(fieldDecl.type, source); fieldDecl.initialization = arrayAlloc; - injectField(annotationNode.up().up(), fieldDecl); + injectFieldSuppressWarnings(annotationNode.up().up(), fieldDecl); } if (method.statements == null) return false; diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java new file mode 100644 index 00000000..b3cfa879 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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 lombok.eclipse.EclipseASTAdapter; +import lombok.eclipse.EclipseASTVisitor; +import lombok.eclipse.EclipseNode; + +import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; +import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.mangosdk.spi.ProviderFor; + +/* + * This class just handles 2 basic error cases. The real meat of eclipse 'val' support is in {@code EclipsePatcher}'s {@code patchHandleVal} method. + */ +@ProviderFor(EclipseASTVisitor.class) +public class HandleVal extends EclipseASTAdapter { + @Override public void visitLocal(EclipseNode localNode, LocalDeclaration local) { + if (local.type instanceof SingleTypeReference) { + char[] token = ((SingleTypeReference)local.type).token; + if (token == null || token.length != 3) return; + else if (token[0] != 'v' || token[1] != 'a' || token[2] != 'l') return; + + boolean variableOfForEach = false; + + if (localNode.directUp().get() instanceof ForeachStatement) { + ForeachStatement fs = (ForeachStatement) localNode.directUp().get(); + variableOfForEach = fs.elementVariable == local; + } + + if (local.initialization == null && !variableOfForEach) { + localNode.addError("'val' on a local variable requires an initializer expression"); + } + + if (local.initialization instanceof ArrayInitializer) { + localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + } + } + } +} |