diff options
| -rw-r--r-- | src/core/lombok/core/AST.java | 28 | ||||
| -rw-r--r-- | src/core/lombok/javac/JavacAST.java | 43 | ||||
| -rw-r--r-- | src/utils/lombok/eclipse/Eclipse.java | 41 | ||||
| -rw-r--r-- | test/core/src/lombok/RunTestsViaEcj.java | 8 | 
4 files changed, 103 insertions, 17 deletions
diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java index 30297418..e6721b80 100644 --- a/src/core/lombok/core/AST.java +++ b/src/core/lombok/core/AST.java @@ -54,7 +54,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,  	private final String fileName;  	private final String packageDeclaration;  	private final ImportList imports; -	Map<N, Void> identityDetector = new IdentityHashMap<N, Void>(); +	Map<N, N> identityDetector = new IdentityHashMap<N, N>();  	private Map<N, L> nodeMap = new IdentityHashMap<N, L>();  	private boolean changed = false; @@ -105,7 +105,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,  	 */  	protected L putInMap(L node) {  		nodeMap.put(node.get(), node); -		identityDetector.put(node.get(), null); +		identityDetector.put(node.get(), node.get());  		return node;  	} @@ -117,7 +117,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,  	/** Clears the registry that avoids endless loops, and empties the node map. The existing node map  	 * object is left untouched, and instead a new map is created. */  	protected void clearState() { -		identityDetector = new IdentityHashMap<N, Void>(); +		identityDetector = new IdentityHashMap<N, N>();  		nodeMap = new IdentityHashMap<N, L>();  	} @@ -127,9 +127,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,  	 * case you should do nothing lest the AST build process loops endlessly.  	 */  	protected boolean setAndGetAsHandled(N node) { -		if (identityDetector.containsKey(node)) return true; -		identityDetector.put(node, null); -		return false; +		return identityDetector.put(node, node) != null;  	}  	public String getFileName() { @@ -234,14 +232,12 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,  				}  			} -			for (Class<?> statementType : getStatementTypes()) { -				if (statementType.isAssignableFrom(t)) { -					f.setAccessible(true); -					fields.add(new FieldAccess(f, dim)); -					break; -				} +			if (shouldDrill(c, t, f.getName())) { +				f.setAccessible(true); +				fields.add(new FieldAccess(f, dim));  			}  		} +		  		getFields(c.getSuperclass(), fields);  	} @@ -258,6 +254,14 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,  	 * though some platforms (such as Eclipse) group these under one common supertype. */  	protected abstract Collection<Class<? extends N>> getStatementTypes(); +	protected boolean shouldDrill(Class<?> parentType, Class<?> childType, String fieldName) { +		for (Class<?> statementType : getStatementTypes()) { +			if (statementType.isAssignableFrom(childType)) return true; +		} +		 +		return false; +	} +	  	/**  	 * buildTree implementation that uses reflection to find all child nodes by way of inspecting  	 * the fields. */ diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 8197dae6..5a91258c 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -24,6 +24,7 @@ package lombok.javac;  import java.lang.reflect.Field;  import java.util.ArrayList;  import java.util.Collection; +import java.util.Collections;  import java.util.List;  import javax.annotation.processing.Messager; @@ -39,6 +40,7 @@ import com.sun.tools.javac.model.JavacElements;  import com.sun.tools.javac.model.JavacTypes;  import com.sun.tools.javac.tree.JCTree;  import com.sun.tools.javac.tree.JCTree.JCCatch; +import com.sun.tools.javac.tree.JCTree.JCTry;  import com.sun.tools.javac.tree.TreeMaker;  import com.sun.tools.javac.tree.JCTree.JCAnnotation;  import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -224,6 +226,46 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {  		return putInMap(new JavacNode(this, local, childNodes, kind));  	} +	private static boolean JCTRY_RESOURCES_FIELD_INITIALIZED; +	private static Field JCTRY_RESOURCES_FIELD; +	 +	@SuppressWarnings("unchecked") +	private static List<JCTree> getResourcesForTryNode(JCTry tryNode) { +		if (!JCTRY_RESOURCES_FIELD_INITIALIZED) { +			try { +				JCTRY_RESOURCES_FIELD = JCTry.class.getField("resources"); +			} catch (NoSuchFieldException ignore) { +				// Java 1.6 or lower won't have this at all. +			} catch (Exception ignore) { +				// Shouldn't happen. Best thing we can do is just carry on and break on try/catch. +			} +			JCTRY_RESOURCES_FIELD_INITIALIZED = true; +		} +		 +		if (JCTRY_RESOURCES_FIELD == null) return Collections.emptyList(); +		Object rv = null; +		try { +			rv = JCTRY_RESOURCES_FIELD.get(tryNode); +		} catch (Exception ignore) {} +		 +		if (rv instanceof List) return (List<JCTree>) rv; +		return Collections.emptyList(); +	} +	 +	private JavacNode buildTry(JCTry tryNode) { +		if (setAndGetAsHandled(tryNode)) return null; +		List<JavacNode> childNodes = new ArrayList<JavacNode>(); +		for (JCTree varDecl : getResourcesForTryNode(tryNode)) { +			if (varDecl instanceof JCVariableDecl) { +				addIfNotNull(childNodes, buildLocalVar((JCVariableDecl) varDecl, Kind.LOCAL)); +			} +		} +		addIfNotNull(childNodes, buildStatement(tryNode.body)); +		for (JCCatch jcc : tryNode.catchers) addIfNotNull(childNodes, buildTree(jcc, Kind.STATEMENT)); +		addIfNotNull(childNodes, buildStatement(tryNode.finalizer)); +		return putInMap(new JavacNode(this, tryNode, childNodes, Kind.STATEMENT)); +	} +	  	private JavacNode buildInitializer(JCBlock initializer) {  		if (setAndGetAsHandled(initializer)) return null;  		List<JavacNode> childNodes = new ArrayList<JavacNode>(); @@ -265,6 +307,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {  		if (statement instanceof JCAnnotation) return null;  		if (statement instanceof JCClassDecl) return buildType((JCClassDecl)statement);  		if (statement instanceof JCVariableDecl) return buildLocalVar((JCVariableDecl)statement, Kind.LOCAL); +		if (statement instanceof JCTry) return buildTry((JCTry) statement);  		if (setAndGetAsHandled(statement)) return null; diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index edfe1536..c2a863d5 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -37,8 +37,10 @@ import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;  import org.eclipse.jdt.internal.compiler.ast.Literal;  import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;  import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.TryStatement;  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.impl.CompilerOptions;  import org.eclipse.jdt.internal.compiler.lookup.TypeIds; @@ -180,8 +182,31 @@ public class Eclipse {  		return null;  	} -	private static int ecjCompilerVersionCached = -1; +	private static long latestEcjCompilerVersionConstantCached = 0; +	 +	public static long getLatestEcjCompilerVersionConstant() { +		if (latestEcjCompilerVersionConstantCached != 0) return latestEcjCompilerVersionConstantCached; +		 +		int highestVersionSoFar = 0; +		for (Field f : ClassFileConstants.class.getDeclaredFields()) { +			try { +				if (f.getName().startsWith("JDK1_")) { +					int thisVersion = Integer.parseInt(f.getName().substring("JDK1_".length())); +					if (thisVersion > highestVersionSoFar) { +						highestVersionSoFar = thisVersion; +						latestEcjCompilerVersionConstantCached = (Long) f.get(null); +					} +				} +			} catch (Exception ignore) {} +		} +		 +		if (highestVersionSoFar > 6 && !ecjSupportsJava7Features()) { +			latestEcjCompilerVersionConstantCached = ClassFileConstants.JDK1_6; +		} +		return latestEcjCompilerVersionConstantCached; +	} +	private static int ecjCompilerVersionCached = -1;  	public static int getEcjCompilerVersion() {  		if (ecjCompilerVersionCached >= 0) return ecjCompilerVersionCached; @@ -194,6 +219,20 @@ public class Eclipse {  		}  		if (ecjCompilerVersionCached < 5) ecjCompilerVersionCached = 5; +		if (!ecjSupportsJava7Features()) ecjCompilerVersionCached = Math.min(6, ecjCompilerVersionCached);  		return ecjCompilerVersionCached;  	} +	 +	/** +	 * Certain ECJ versions that only go up to -source 6 report that they support -source 7 and even fail to error when -source 7 is applied. +	 * We detect this and correctly say that no more than -source 6 is supported. (when this is the case, this method returns false). +	 */ +	private static boolean ecjSupportsJava7Features() { +		try { +			TryStatement.class.getDeclaredField("resources"); +			return true; +		} catch (NoSuchFieldException e) { +			return false; +		} +	}  } diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index ca443620..12f2e252 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -33,6 +33,7 @@ import java.util.Locale;  import java.util.Map;  import java.util.concurrent.atomic.AtomicReference; +import lombok.eclipse.Eclipse;  import lombok.javac.CapturingDiagnosticListener.CompilerMessage;  import org.eclipse.jdt.core.compiler.CategorizedProblem; @@ -43,7 +44,6 @@ import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;  import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;  import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;  import org.eclipse.jdt.internal.compiler.batch.FileSystem; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;  import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;  import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;  import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; @@ -51,9 +51,9 @@ import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;  public class RunTestsViaEcj extends AbstractRunTests {  	protected CompilerOptions ecjCompilerOptions() {  		CompilerOptions options = new CompilerOptions(); -		options.complianceLevel = ClassFileConstants.JDK1_6; -		options.sourceLevel = ClassFileConstants.JDK1_6; -		options.targetJDK = ClassFileConstants.JDK1_6; +		options.complianceLevel = Eclipse.getLatestEcjCompilerVersionConstant(); +		options.sourceLevel = Eclipse.getLatestEcjCompilerVersionConstant(); +		options.targetJDK = Eclipse.getLatestEcjCompilerVersionConstant();  		options.parseLiteralExpressionsAsConstants = true;  		options.inlineJsrBytecode = true;  		options.reportUnusedDeclaredThrownExceptionExemptExceptionAndThrowable = false;  | 
