Index: src/test/org/codehaus/groovy/ast/ASTTest.java
===================================================================
--- src/test/org/codehaus/groovy/ast/ASTTest.java	(Revision 0)
+++ src/test/org/codehaus/groovy/ast/ASTTest.java	(Revision 865)
@@ -0,0 +1,28 @@
+package org.codehaus.groovy.ast;
+
+import junit.framework.TestCase;
+
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.control.SourceUnit;
+
+/**
+ * Base class for every TestCase that uses an AST
+ * 
+ * @author <a href="mailto:martin.kempf@gmail.com">Martin Kempf</a>
+ *
+ */
+public class ASTTest extends TestCase {
+
+	public ModuleNode getAST(String source, int untilPhase) {
+		SourceUnit unit = SourceUnit.create("Test",source);
+		CompilationUnit compUnit = new CompilationUnit();
+		compUnit.addSource(unit);
+	    compUnit.compile(untilPhase);
+	    return unit.getAST();
+	}
+	
+	public ModuleNode getAST(String source) {
+		return getAST(source, Phases.SEMANTIC_ANALYSIS);
+	}
+}

Index: src/test/org/codehaus/groovy/ast/LineColumnChecker.java
===================================================================
--- src/test/org/codehaus/groovy/ast/LineColumnChecker.java	(Revision 0)
+++ src/test/org/codehaus/groovy/ast/LineColumnChecker.java	(Revision 865)
@@ -0,0 +1,367 @@
+package org.codehaus.groovy.ast;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BitwiseNegationExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ClosureListExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MapExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.MethodPointerExpression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.PostfixExpression;
+import org.codehaus.groovy.ast.expr.PrefixExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.RangeExpression;
+import org.codehaus.groovy.ast.expr.RegexExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.SpreadMapExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TernaryExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.UnaryMinusExpression;
+import org.codehaus.groovy.ast.expr.UnaryPlusExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.control.SourceUnit;
+
+/**
+ * Tests the LineColumn information of the groovy source obtained in the
+ * source parameter of the constructor
+ * 
+ * @author <a href="mailto:martin.kempf@gmail.com">Martin Kempf</a>
+ *
+ */
+public class LineColumnChecker extends ASTTest {
+	
+	private LineCheckVisitor visitor;
+	private String name;
+	private String source;
+	private String[] expected;
+	
+	public LineColumnChecker(String name, String source, String expected) {
+		this.name = name;
+		this.source = source;
+		this.expected = expected.split(";");
+		// Set Method to call for JUnit
+		setName("testLineColumn");
+	}
+	
+	public void setUp() {
+		visitor = new LineCheckVisitor();
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void testLineColumn() {
+		visitor.visitModuleNode(getAST(source));
+		String was = visitor.getASTString();
+		//comment out next line to view the output of the visitor
+		//System.out.println(name + ": " + was);
+		for (int i = 0; i < expected.length; i++) {
+			assertTrue(expected[i] + " not found in" + was, was.contains(expected[i].trim()));
+		}
+	}
+}
+
+/**
+ * 
+ * Visitor to write for each visited node a string like:
+ * [<NodeType>,(<line>:<column>),(<lastLine>:<lastColumn>)]
+ * 
+ */
+class LineCheckVisitor extends ClassCodeVisitorSupport {
+	
+	private StringBuilder astString = new StringBuilder();
+	
+	public String getASTString() {
+		return astString.toString();
+	}
+
+	protected void visitStatement(Statement statement) {
+		visitNode(statement);
+	}
+
+	protected void visitNode(ASTNode node) {
+		String nodeName = node.getClass().getName();
+		//get classname without package
+		nodeName = nodeName.substring(nodeName.lastIndexOf(".") + 1,nodeName.length());
+		astString.append("[");
+		astString.append(nodeName);
+		astString.append(",(");
+		astString.append(node.getLineNumber());
+		astString.append(":");
+		astString.append(node.getColumnNumber());
+		astString.append("),(");
+		astString.append(node.getLastLineNumber());
+		astString.append(":");
+		astString.append(node.getLastColumnNumber());
+		astString.append(")]");
+		//String of each node looks like: [AssertStatement,(1:1),(1:20)]
+	}
+
+	public SourceUnit getSourceUnit() {
+		return null;
+	}
+
+	public void visitModuleNode(ModuleNode moduleNode) {
+		List classes = moduleNode.getClasses();
+		for (Iterator classIt = classes.iterator(); classIt.hasNext();) {
+			ClassNode classNode = (ClassNode)classIt.next();
+			if (!classNode.isScript()) {
+				visitClass(classNode);
+			} else {
+				List methods = moduleNode.getMethods();
+				for (Iterator methodIt = methods.iterator(); methodIt.hasNext();) {
+					MethodNode method = (MethodNode)methodIt.next();
+					visitMethod(method);	
+				}
+			}
+		}
+		//visit Statements that are not inside a class
+		if (!moduleNode.getStatementBlock().isEmpty()) {
+			visitBlockStatement(moduleNode.getStatementBlock());
+		}
+	}
+
+	public void visitClass(ClassNode node) {
+		visitNode(node);
+		super.visitClass(node);
+	}
+
+	public void visitAnnotations(AnnotatedNode node) {
+        Map annotionMap = node.getAnnotations();
+        if (annotionMap.isEmpty()) return;
+		visitNode(node);
+		super.visitAnnotations(node);
+	}
+
+	public void visitConstructor(ConstructorNode node) {
+		visitNode(node);
+		super.visitConstructor(node);
+	}
+
+	public void visitMethod(MethodNode node) {
+		visitNode(node);
+		super.visitMethod(node);
+	}
+
+	public void visitField(FieldNode node) {
+		// Do not visit fields which are manually added due to optimization
+		if (!node.getName().startsWith("$")) {
+			visitNode(node);
+			super.visitField(node);
+		}
+	}
+
+	public void visitProperty(PropertyNode node) {
+		// do nothing, also visited as FieldNode
+	}
+	
+	/*
+	 * Statements
+	 * 
+	 * Statements are visited in ClassCodeVisitorSupport and call there
+	 * visitStatement(Statement statement) which is overridden in this class
+	 */
+
+	/*
+	 * Expressions
+	 */
+	public void visitMethodCallExpression(MethodCallExpression call) {
+		visitNode(call);
+		super.visitMethodCallExpression(call);
+	}
+
+	public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
+		visitNode(call);
+		super.visitStaticMethodCallExpression(call);
+	}
+
+	public void visitConstructorCallExpression(ConstructorCallExpression call) {
+		visitNode(call);
+		super.visitConstructorCallExpression(call);
+	}
+
+	public void visitBinaryExpression(BinaryExpression expression) {
+		visitNode(expression);
+		super.visitBinaryExpression(expression);
+	}
+
+	public void visitTernaryExpression(TernaryExpression expression) {
+		visitNode(expression);
+		super.visitTernaryExpression(expression);
+	}
+
+	public void visitPostfixExpression(PostfixExpression expression) {
+		visitNode(expression);
+		super.visitPostfixExpression(expression);
+	}
+
+	public void visitPrefixExpression(PrefixExpression expression) {
+		visitNode(expression);
+		super.visitPrefixExpression(expression);
+	}
+
+	public void visitBooleanExpression(BooleanExpression expression) {
+		visitNode(expression);
+		super.visitBooleanExpression(expression);
+	}
+
+	public void visitNotExpression(NotExpression expression) {
+		visitNode(expression);
+		super.visitNotExpression(expression);
+	}
+
+	public void visitClosureExpression(ClosureExpression expression) {
+		visitNode(expression);
+		super.visitClosureExpression(expression);
+	}
+
+	public void visitTupleExpression(TupleExpression expression) {
+		visitNode(expression);
+		super.visitTupleExpression(expression);
+	}
+
+	public void visitListExpression(ListExpression expression) {
+		visitNode(expression);
+		super.visitListExpression(expression);
+	}
+
+	public void visitArrayExpression(ArrayExpression expression) {
+		visitNode(expression);
+		super.visitArrayExpression(expression);
+	}
+
+	public void visitMapExpression(MapExpression expression) {
+		visitNode(expression);
+		super.visitMapExpression(expression);
+	}
+
+	public void visitMapEntryExpression(MapEntryExpression expression) {
+		visitNode(expression);
+		super.visitMapEntryExpression(expression);
+	}
+
+	public void visitRangeExpression(RangeExpression expression) {
+		visitNode(expression);
+		super.visitRangeExpression(expression);
+	}
+
+	public void visitSpreadExpression(SpreadExpression expression) {
+		visitNode(expression);
+		super.visitSpreadExpression(expression);
+	}
+
+	public void visitSpreadMapExpression(SpreadMapExpression expression) {
+		visitNode(expression);
+		super.visitSpreadMapExpression(expression);
+	}
+
+	public void visitMethodPointerExpression(MethodPointerExpression expression) {
+		visitNode(expression);
+		super.visitMethodPointerExpression(expression);
+	}
+
+	public void visitBitwiseNegationExpression(
+			BitwiseNegationExpression expression) {
+		visitNode(expression);
+		super.visitBitwiseNegationExpression(expression);
+	}
+
+	public void visitCastExpression(CastExpression expression) {
+		visitNode(expression);
+		super.visitCastExpression(expression);
+	}
+
+	public void visitConstantExpression(ConstantExpression expression) {
+		visitNode(expression);
+		super.visitConstantExpression(expression);
+	}
+
+	public void visitClassExpression(ClassExpression expression) {
+		visitNode(expression);
+		super.visitClassExpression(expression);
+	}
+
+	public void visitVariableExpression(VariableExpression expression) {
+		visitNode(expression);
+		super.visitVariableExpression(expression);
+	}
+
+	public void visitDeclarationExpression(DeclarationExpression expression) {
+		//visitNode(expression); is visited afterwards in BinaryExpression. Because
+		//super.visitDeclarationExpression calls visitBinaryExpression
+		super.visitDeclarationExpression(expression);
+	}
+
+	public void visitPropertyExpression(PropertyExpression expression) {
+		visitNode(expression);
+		super.visitPropertyExpression(expression);
+	}
+
+	public void visitAttributeExpression(AttributeExpression expression) {
+		visitNode(expression);
+		super.visitAttributeExpression(expression);
+	}
+
+	public void visitFieldExpression(FieldExpression expression) {
+		visitNode(expression);
+		super.visitFieldExpression(expression);
+	}
+
+	public void visitRegexExpression(RegexExpression expression) {
+		visitNode(expression);
+		super.visitRegexExpression(expression);
+	}
+
+	public void visitGStringExpression(GStringExpression expression) {
+		visitNode(expression);
+		super.visitGStringExpression(expression);
+	}
+
+	public void visitArgumentlistExpression(ArgumentListExpression ale) {
+		//visitNode(ale); is visited afterwards in TupleExpression. Because
+		//super.visitArgumentlistExpression calls visitTupleExpression
+		super.visitArgumentlistExpression(ale);
+	}
+
+	public void visitShortTernaryExpression(ElvisOperatorExpression expression) {
+		visitNode(expression);
+		super.visitShortTernaryExpression(expression);
+	}
+
+	public void visitUnaryPlusExpression(UnaryPlusExpression expression) {
+		visitNode(expression);
+		super.visitUnaryPlusExpression(expression);
+	}
+
+	public void visitUnaryMinusExpression(UnaryMinusExpression expression) {
+		visitNode(expression);
+		super.visitUnaryMinusExpression(expression);
+	}
+
+	public void visitClosureListExpression(ClosureListExpression cle) {
+		visitNode(cle);
+		super.visitClosureListExpression(cle);
+	}
+}

Index: src/test/org/codehaus/groovy/ast/LineColumnCheckTestSuite.java
===================================================================
--- src/test/org/codehaus/groovy/ast/LineColumnCheckTestSuite.java	(Revision 0)
+++ src/test/org/codehaus/groovy/ast/LineColumnCheckTestSuite.java	(Revision 865)
@@ -0,0 +1,80 @@
+package org.codehaus.groovy.ast;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+import junit.framework.TestSuite;
+
+/**
+ * Tests the LineColumn information in file specified in TEST_FILE_PATH
+ * 
+ * The file in the specified path should look like:
+ * 
+ * ###<testname>:::
+ * <source code from which the AST will be built>
+ * :::<expected AST output>
+ * 
+ * The section above can be repeated for every new TestCase
+ * 
+ * The AST output from the visitor is quite big. Also for small source code snippets. Therefore
+ * it is possible to only specify the nodes that you wan't to check and separate them with a semicolon.
+ * A semicolon is also needed when you begin with a new line.
+ * Bsp: 
+ * [TryCatchStatement,(1:1),(9:2)][BlockStatement,(1:5),(3:3)];
+ * [CatchStatement,(3:3),(5:3)][BlockStatement,(3:12),(5:3)];
+ * [CatchStatement,(5:3),(7:3)][BlockStatement,(5:12),(7:3)];
+ * [BlockStatement,(7:3),(9:2)][BlockStatement,(7:11),(9:2)]
+ * 
+ * [<NodeType>,(<line>:<column>),(<lastLine>:<lastColumn>)]
+ * 
+ * @author <a href="mailto:martin.kempf@gmail.com">Martin Kempf</a>
+ *
+ */
+public class LineColumnCheckTestSuite extends TestSuite {
+
+	public static final String TEST_FILE_PATH = "./src/test/org/codehaus/groovy/ast/LineColumnCheck.txt";
+
+	public static TestSuite suite() {
+		TestSuite ts = new TestSuite("LineColumnCheckTestSuite");
+		String content = "";
+		try {
+			content = getContent(new FileReader(TEST_FILE_PATH));
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		}
+		String[] tests = content.split("###");
+		String testName = "";
+		String source = "";
+		String expected = "";
+		for (int i = 0; i < tests.length; i++) {
+			String[] slicedTests = tests[i].split(":::");
+			for (int ii = 0; ii < slicedTests.length; ii++) {
+				if (ii%3 == 0) {
+					testName = slicedTests[ii];
+				} else if (ii%3 == 1) {
+					source = slicedTests[ii].trim();
+				} else if (ii%3 == 2) {
+					expected = slicedTests[ii].trim();
+					ts.addTest(new LineColumnChecker(testName, source, expected));
+				}
+			}
+		}
+		return ts;
+	}
+
+	private static String getContent(Reader reader) {
+		int character;
+		StringBuilder content = new StringBuilder();
+		try {
+			while ((character = reader.read()) != -1) {
+				content.append((char) character);
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return content.toString();
+	}
+
+}

Index: src/test/JavaSourceCodehausPackagesSuite.java
===================================================================
--- src/test/JavaSourceCodehausPackagesSuite.java	(Revision 730)
+++ src/test/JavaSourceCodehausPackagesSuite.java	(Revision 865)
@@ -8,6 +8,8 @@
 import org.codehaus.groovy.antlr.SourceBufferTest;
 import org.codehaus.groovy.antlr.treewalker.*;
 import org.codehaus.groovy.ast.ClassNodeTest;
+import org.codehaus.groovy.ast.LineColumnCheckTestSuite;
+import org.codehaus.groovy.ast.MethodCallExpressionTest;
 import org.codehaus.groovy.ast.MethodNodeTest;
 import org.codehaus.groovy.ast.ModuleNodeTest;
 import org.codehaus.groovy.ast.VariableExpressionTest;
@@ -88,6 +90,7 @@
         suite.addTestSuite(CompilerConfigurationTest.class);
         suite.addTestSuite(MethodNodeTest.class);
         suite.addTestSuite(VariableExpressionTest.class);
+        suite.addTest(LineColumnCheckTestSuite.suite());
         return suite;
     }
 }
 