groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sun...@apache.org
Subject [groovy] branch master updated: GROOVY-9168: emit more specific error for use of uninitialized this(closes #963)
Date Sat, 13 Jul 2019 18:18:15 GMT
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 09ac1a5  GROOVY-9168: emit more specific error for use of uninitialized this(closes #963)
09ac1a5 is described below

commit 09ac1a527615d103779464ee0870ea2d0ae4ce93
Author: Eric Milles <eric.milles@thomsonreuters.com>
AuthorDate: Sun Jul 14 02:17:55 2019 +0800

    GROOVY-9168: emit more specific error for use of uninitialized this(closes #963)
---
 .../groovy/classgen/InnerClassVisitor.java         | 122 +++--
 .../groovy/classgen/InnerClassVisitorHelper.java   |  17 +-
 .../org/codehaus/groovy/classgen/Verifier.java     | 130 ++++--
 .../groovy/classgen/VerifierCodeVisitor.java       |  11 +-
 .../codehaus/groovy/control/StaticVerifier.java    | 146 ++----
 .../groovy/tools/javac/JavaStubGenerator.java      |  16 +-
 src/test/gls/innerClass/InnerClassTest.groovy      | 515 ++++++++++++---------
 .../groovy/bugs/ConstructorParameterBug.groovy     |  47 +-
 src/test/groovy/bugs/ConstructorThisCallBug.groovy |  80 ++--
 .../{Groovy5259Bug.groovy => Groovy5259.groovy}    |  23 +-
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   | 114 ++---
 11 files changed, 643 insertions(+), 578 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
index 5416a3f..63faa85 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
@@ -48,18 +48,13 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
-import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.nonGeneric;
-
 public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcodes {
 
-    private final SourceUnit sourceUnit;
     private ClassNode classNode;
-    private FieldNode thisField;
-    private MethodNode currentMethod;
     private FieldNode currentField;
-    private boolean processingObjInitStatements;
-    private boolean inClosure;
+    private MethodNode currentMethod;
+    private final SourceUnit sourceUnit;
+    private boolean inClosure, processingObjInitStatements;
 
     public InnerClassVisitor(CompilationUnit cu, SourceUnit su) {
         sourceUnit = su;
@@ -73,12 +68,11 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
     @Override
     public void visitClass(ClassNode node) {
         classNode = node;
-        thisField = null;
         InnerClassNode innerClass = null;
         if (!node.isEnum() && !node.isInterface() && node instanceof InnerClassNode) {
             innerClass = (InnerClassNode) node;
-            if (!isStatic(innerClass) && innerClass.getVariableScope() == null) {
-                thisField = innerClass.addField("this$0", ACC_FINAL | ACC_SYNTHETIC, node.getOuterClass().getPlainNodeReference(), null);
+            if (innerClass.getVariableScope() == null && (innerClass.getModifiers() & ACC_STATIC) == 0) {
+                innerClass.addField("this$0", ACC_FINAL | ACC_SYNTHETIC, node.getOuterClass().getPlainNodeReference(), null);
             }
         }
 
@@ -159,45 +153,24 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
 
         VariableScope scope = innerClass.getVariableScope();
         if (scope == null) return;
-
-        int additionalParamCount = scope.getReferencedLocalVariablesCount();
-        boolean[] precedesSuperOrThisCall = new boolean[1];
-        if (currentMethod instanceof ConstructorNode) {
-            ConstructorNode ctor = (ConstructorNode) currentMethod;
-            GroovyCodeVisitor visitor = new CodeVisitorSupport() {
-                @Override
-                public void visitConstructorCallExpression(ConstructorCallExpression cce) {
-                    if (cce == call) {
-                        precedesSuperOrThisCall[0] = true;
-                    } else {
-                        super.visitConstructorCallExpression(cce);
-                    }
-                }
-            };
-            if (ctor.firstStatementIsSpecialConstructorCall()) currentMethod.getFirstStatement().visit(visitor);
-            Arrays.stream(ctor.getParameters()).filter(Parameter::hasInitialExpression).forEach(p -> p.getInitialExpression().visit(visitor));
-        }
-        if (!precedesSuperOrThisCall[0]) additionalParamCount += 1;
+        boolean isStatic = !inClosure && isStatic(innerClass, scope, call);
 
         // expressions = constructor call arguments
         List<Expression> expressions = ((TupleExpression) call.getArguments()).getExpressions();
         // block = init code for the constructor we produce
         BlockStatement block = new BlockStatement();
         // parameters = parameters of the constructor
+        int additionalParamCount = (isStatic ? 0 : 1) + scope.getReferencedLocalVariablesCount();
         List<Parameter> parameters = new ArrayList<>(expressions.size() + additionalParamCount);
         // superCallArguments = arguments for the super call == the constructor call arguments
         List<Expression> superCallArguments = new ArrayList<>(expressions.size());
 
-        // first we add a super() call for all expressions given in the
-        // constructor call expression
-        int pCount = additionalParamCount;
-        for (Expression expr : expressions) {
-            pCount++;
-            // add one parameter for each expression in the
-            // constructor call
-            Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + pCount);
+        // first we add a super() call for all expressions given in the constructor call expression
+        for (int i = 0, n = expressions.size(); i < n; i += 1) {
+            // add one parameter for each expression in the constructor call
+            Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + additionalParamCount + i);
             parameters.add(param);
-            // add to super call
+            // add the corresponsing argument to the super constructor call
             superCallArguments.add(new VariableExpression(param));
         }
 
@@ -209,45 +182,38 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
 
         block.addStatement(new ExpressionStatement(cce));
 
-        pCount = 0;
-        boolean isStatic = isStaticThis(innerClass, scope);
-        ClassNode outerClassType;
-        if (!isStatic && inClosure) {
-            outerClassType = ClassHelper.CLOSURE_TYPE.getPlainNodeReference();
-        } else {
-            outerClassType = getClassNode(outerClass, isStatic).getPlainNodeReference();
-        }
-        if (!precedesSuperOrThisCall[0]) {
+        int pCount = 0;
+        if (!isStatic) {
             // need to pass "this" to access unknown methods/properties
             expressions.add(pCount, VariableExpression.THIS_EXPRESSION);
 
-            Parameter thisParameter = new Parameter(outerClassType, "p" + pCount);
-            parameters.add(pCount, thisParameter);
+            ClassNode enclosingType = (inClosure ? ClassHelper.CLOSURE_TYPE : outerClass).getPlainNodeReference();
+            Parameter thisParameter = new Parameter(enclosingType, "p" + pCount);
+            parameters.add(pCount++, thisParameter);
 
             // "this" reference is saved in a field named "this$0"
-            thisField = innerClass.addField("this$0", ACC_FINAL | ACC_SYNTHETIC, outerClassType, null);
+            FieldNode thisField = innerClass.addField("this$0", ACC_FINAL | ACC_SYNTHETIC, enclosingType, null);
             addFieldInit(thisParameter, thisField, block);
-        }/* else {
-            thisField = innerClass.addField("this$0", ACC_FINAL | ACC_SYNTHETIC, nonGeneric(ClassHelper.CLASS_Type), classX(outerClassType));
-        }*/
+        }
 
         // for each shared variable, add a Reference field
         for (Iterator<Variable> it = scope.getReferencedLocalVariablesIterator(); it.hasNext();) {
-            pCount++;
             Variable var = it.next();
+
             VariableExpression ve = new VariableExpression(var);
             ve.setClosureSharedVariable(true);
             ve.setUseReferenceDirectly(true);
             expressions.add(pCount, ve);
 
-            ClassNode rawReferenceType = ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
-            Parameter p = new Parameter(rawReferenceType, "p" + pCount);
-            parameters.add(pCount, p);
+            ClassNode referenceType = ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
+            Parameter p = new Parameter(referenceType, "p" + pCount);
             p.setOriginType(var.getOriginType());
+            parameters.add(pCount++, p);
+
             VariableExpression initial = new VariableExpression(p);
             initial.setSynthetic(true);
             initial.setUseReferenceDirectly(true);
-            FieldNode pField = innerClass.addFieldFirst(ve.getName(), ACC_PUBLIC | ACC_SYNTHETIC, rawReferenceType, initial);
+            FieldNode pField = innerClass.addFieldFirst(ve.getName(), ACC_PUBLIC | ACC_SYNTHETIC, referenceType, initial);
             pField.setHolder(true);
             pField.setOriginType(ClassHelper.getWrapper(var.getOriginType()));
         }
@@ -255,17 +221,35 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
         innerClass.addConstructor(ACC_SYNTHETIC, parameters.toArray(Parameter.EMPTY_ARRAY), ClassNode.EMPTY_ARRAY, block);
     }
 
-    private boolean isStaticThis(InnerClassNode innerClass, VariableScope scope) {
-        if (inClosure) return false;
-        boolean ret = innerClass.isStaticClass();
-        if (innerClass.getEnclosingMethod() != null) {
-            ret = ret || innerClass.getEnclosingMethod().isStatic();
-        } else if (currentField != null) {
-            ret = ret || currentField.isStatic();
-        } else if (currentMethod != null && "<clinit>".equals(currentMethod.getName())) {
-            ret = true;
+    private boolean isStatic(InnerClassNode innerClass, VariableScope scope, ConstructorCallExpression call) {
+        boolean isStatic = innerClass.isStaticClass();
+        if (!isStatic) {
+            if (currentMethod != null) {
+                if (currentMethod instanceof ConstructorNode) {
+                    boolean[] precedesSuperOrThisCall = new boolean[1];
+                    ConstructorNode ctor = (ConstructorNode) currentMethod;
+                    GroovyCodeVisitor visitor = new CodeVisitorSupport() {
+                        @Override
+                        public void visitConstructorCallExpression(ConstructorCallExpression cce) {
+                            if (cce == call) {
+                                precedesSuperOrThisCall[0] = true;
+                            } else {
+                                super.visitConstructorCallExpression(cce);
+                            }
+                        }
+                    };
+                    if (ctor.firstStatementIsSpecialConstructorCall()) currentMethod.getFirstStatement().visit(visitor);
+                    Arrays.stream(ctor.getParameters()).filter(Parameter::hasInitialExpression).forEach(p -> p.getInitialExpression().visit(visitor));
+
+                    isStatic = precedesSuperOrThisCall[0];
+                } else {
+                    isStatic = currentMethod.isStatic();
+                }
+            } else if (currentField != null) {
+                isStatic = currentField.isStatic();
+            }
         }
-        return ret;
+        return isStatic;
     }
 
     // this is the counterpart of addThisReference(). To non-static inner classes, outer this should be
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
index 9452768..bc9292a 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
@@ -24,12 +24,10 @@ import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.VariableScope;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.FieldExpression;
 import org.codehaus.groovy.ast.expr.GStringExpression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
@@ -45,7 +43,12 @@ import org.objectweb.asm.Opcodes;
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+
 public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
+
     protected static void setPropertyGetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
         List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
         gStringStrings.add(new ConstantExpression(""));
@@ -102,9 +105,7 @@ public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
     }
 
     protected static boolean isStatic(InnerClassNode node) {
-        VariableScope scope = node.getVariableScope();
-        if (scope != null) return scope.getParent().isInStaticContext();
-        return (node.getModifiers() & Opcodes.ACC_STATIC) != 0;
+        return node.getDeclaredField("this$0") == null;
     }
 
     protected static ClassNode getClassNode(ClassNode node, boolean isStatic) {
@@ -122,11 +123,7 @@ public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
     }
 
     protected static void addFieldInit(Parameter p, FieldNode fn, BlockStatement block) {
-        VariableExpression ve = new VariableExpression(p);
-        FieldExpression fe = new FieldExpression(fn);
-        block.addStatement(new ExpressionStatement(
-                new BinaryExpression(fe, Token.newSymbol(Types.ASSIGN, -1, -1), ve)
-        ));
+        block.addStatement(assignS(fieldX(fn), varX(p)));
     }
 
     protected static boolean shouldHandleImplicitThisForInnerClass(ClassNode cn) {
diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index f55ba78..d821a3f 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -20,6 +20,7 @@ package org.codehaus.groovy.classgen;
 
 import groovy.lang.GroovyClassLoader;
 import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
 import groovy.lang.MetaClass;
 import groovy.transform.Generated;
 import groovy.transform.Internal;
@@ -32,6 +33,7 @@ import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.CodeVisitorSupport;
 import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.DynamicVariable;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.GroovyClassVisitor;
@@ -56,7 +58,6 @@ import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.ast.tools.PropertyNodeUtils;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.classgen.asm.MopWriter;
 import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.ClassNodeSkip;
@@ -628,61 +629,101 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
 
     @Override
     public void visitConstructor(ConstructorNode node) {
-        GroovyCodeVisitor checkSuper = new CodeVisitorSupport() {
-            boolean firstMethodCall = true;
-            String type = null;
+        Statement stmt = node.getCode();
+        if (stmt != null) {
+            stmt.visit(new VerifierCodeVisitor(getClassNode()));
+            // check for uninitialized-this references
+            stmt.visit(new CodeVisitorSupport() {
+                @Override
+                public void visitClosureExpression(ClosureExpression ce) {
+                    boolean oldInClosure = inClosure;
+                    inClosure = true;
+                    super.visitClosureExpression(ce);
+                    inClosure = oldInClosure;
+                }
 
-            @Override
-            public void visitMethodCallExpression(MethodCallExpression call) {
-                if (!firstMethodCall) return;
-                firstMethodCall = false;
-                String name = call.getMethodAsString();
-                // the name might be null if the method name is a GString for example
-                if (name == null) return;
-                if (!name.equals("super") && !name.equals("this")) return;
-                type = name;
-                call.getArguments().visit(this);
-                type = null;
-            }
+                @Override
+                public void visitConstructorCallExpression(ConstructorCallExpression cce) {
+                    boolean oldIsSpecialConstructorCall = inSpecialConstructorCall;
+                    inSpecialConstructorCall |= cce.isSpecialCall();
+                    super.visitConstructorCallExpression(cce);
+                    inSpecialConstructorCall = oldIsSpecialConstructorCall;
+                }
 
-            @Override
-            public void visitConstructorCallExpression(ConstructorCallExpression call) {
-                if (!call.isSpecialCall()) return;
-                type = call.getText();
-                call.getArguments().visit(this);
-                type = null;
-            }
+                @Override
+                public void visitMethodCallExpression(MethodCallExpression mce) {
+                    if (inSpecialConstructorCall && isThisObjectExpression(mce)) {
+                        MethodNode methodTarget = mce.getMethodTarget();
+                        if (methodTarget == null || !(methodTarget.isStatic() || classNode.getOuterClasses().contains(methodTarget.getDeclaringClass()))) {
+                            if (!mce.isImplicitThis()) {
+                                throw newVariableError(mce.getObjectExpression().getText(), mce.getObjectExpression());
+                            } else {
+                                throw newVariableError(mce.getMethodAsString(), mce.getMethod());
+                            }
+                        }
+                        mce.getMethod().visit(this);
+                        mce.getArguments().visit(this);
+                    } else {
+                        super.visitMethodCallExpression(mce);
+                    }
+                }
 
-            @Override
-            public void visitVariableExpression(VariableExpression expression) {
-                if (type == null) return;
-                String name = expression.getName();
-                if (!name.equals("this") && !name.equals("super")) return;
-                throw new RuntimeParserException("cannot reference " + name + " inside of " + type + "(....) before supertype constructor has been called", expression);
-            }
-        };
-        Statement s = node.getCode();
-        if (s == null) {
-            return;
-        } else {
-            s.visit(new VerifierCodeVisitor(this));
+                @Override
+                public void visitVariableExpression(VariableExpression ve) {
+                    // before this/super ctor call completes, only params and static or outer members are accessible
+                    if (inSpecialConstructorCall && (ve.isThisExpression() || ve.isSuperExpression() || isNonStaticMemberAccess(ve))) {
+                        throw newVariableError(ve.getName(), ve.getLineNumber() > 0 ? ve : node); // TODO: context for default argument
+                    }
+                }
+
+                //
+
+                private boolean inClosure, inSpecialConstructorCall;
+
+                private boolean isNonStaticMemberAccess(VariableExpression ve) {
+                    Variable variable = ve.getAccessedVariable();
+                    return !inClosure && variable != null && !isStatic(variable.getModifiers())
+                        && !(variable instanceof DynamicVariable) && !(variable instanceof Parameter);
+                }
+
+                private boolean isThisObjectExpression(MethodCallExpression mce) {
+                    if (mce.isImplicitThis()) {
+                        return true;
+                    } else if (mce.getObjectExpression() instanceof VariableExpression) {
+                        VariableExpression var = (VariableExpression) mce.getObjectExpression();
+                        return var.isThisExpression() || var.isSuperExpression();
+                    } else {
+                        return false;
+                    }
+                }
+
+                private GroovyRuntimeException newVariableError(String name, ASTNode node) {
+                    RuntimeParserException rpe = new RuntimeParserException("Cannot reference '" + name +
+                            "' before supertype constructor has been called. Possible causes:\n" +
+                            "You attempted to access an instance field, method, or property.\n" +
+                            "You attempted to construct a non-static inner class.", node);
+                    rpe.setModule(getClassNode().getModule());
+                    return rpe;
+                }
+            });
         }
-        s.visit(checkSuper);
     }
 
     @Override
     public void visitMethod(MethodNode node) {
-        //GROOVY-3712 - if it's an MOP method, it's an error as they aren't supposed to exist before ACG is invoked
+        // GROOVY-3712 - if it's an MOP method, it's an error as they aren't supposed to exist before ACG is invoked
         if (MopWriter.isMopMethod(node.getName())) {
-            throw new RuntimeParserException("Found unexpected MOP methods in the class node for " + classNode.getName() +
-                    "(" + node.getName() + ")", classNode);
+            throw new RuntimeParserException("Found unexpected MOP methods in the class node for " + classNode.getName() + "(" + node.getName() + ")", classNode);
         }
-        this.methodNode = node;
+
         adjustTypesIfStaticMainMethod(node);
+        this.methodNode = node;
         addReturnIfNeeded(node);
-        Statement statement;
-        statement = node.getCode();
-        if (statement != null) statement.visit(new VerifierCodeVisitor(this));
+
+        Statement stmt = node.getCode();
+        if (stmt != null) {
+            stmt.visit(new VerifierCodeVisitor(getClassNode()));
+        }
     }
 
     private static void adjustTypesIfStaticMainMethod(MethodNode node) {
@@ -865,6 +906,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                                 localVariable = localVarX(p.getName(), p.getType());
                                 localVariable.setModifiers(p.getModifiers());
                                 blockScope.putDeclaredVariable(localVariable);
+                                localVariable.setInStaticContext(blockScope.isInStaticContext());
                                 code.addStatement(declS(localVariable, p.getInitialExpression()));
                             }
                             if (!localVariable.isClosureSharedVariable()) {
diff --git a/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
index 2cb9fc2..2fe6a17 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
@@ -29,19 +29,18 @@ import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.syntax.RuntimeParserException;
-import org.objectweb.asm.Opcodes;
 
 /**
  * Performs various checks on code inside methods and constructors
  * including checking for valid field, variables names etc. that
  * would otherwise lead to invalid code.
  */
-public class VerifierCodeVisitor extends CodeVisitorSupport implements Opcodes {
+public class VerifierCodeVisitor extends CodeVisitorSupport {
 
-    private final Verifier verifier;
+    private final ClassNode classNode;
 
-    VerifierCodeVisitor(Verifier verifier) {
-        this.verifier = verifier;
+    public VerifierCodeVisitor(ClassNode classNode) {
+        this.classNode = classNode;
     }
 
     public void visitForLoop(ForStatement expression) {
@@ -72,7 +71,7 @@ public class VerifierCodeVisitor extends CodeVisitorSupport implements Opcodes {
 
     public void visitConstructorCallExpression(ConstructorCallExpression call) {
         ClassNode callType = call.getType();
-        if (callType.isEnum() && !callType.equals(verifier.getClassNode())) {
+        if (callType.isEnum() && !callType.equals(classNode)) {
             throw new RuntimeParserException("Enum constructor calls are only allowed inside the enum class", call);
         }
     }
diff --git a/src/main/java/org/codehaus/groovy/control/StaticVerifier.java b/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
index a0442a4..2fdee68 100644
--- a/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
+++ b/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
@@ -20,48 +20,34 @@ package org.codehaus.groovy.control;
 
 import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
 import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.CodeVisitorSupport;
 import org.codehaus.groovy.ast.DynamicVariable;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.expr.ClosureExpression;
 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
-
-import static org.apache.groovy.ast.tools.ClassNodeUtils.isInnerClass;
 
 /**
- * Verifier to check non-static access in static contexts
+ * Checks for dynamic variables in static contexts.
  */
 public class StaticVerifier extends ClassCodeVisitorSupport {
-    private boolean inSpecialConstructorCall;
-    private boolean inPropertyExpression; // TODO use it or lose it
-    private boolean inClosure;
-    private MethodNode currentMethod;
-    private SourceUnit source;
+    private boolean inClosure, inSpecialConstructorCall;
+    private MethodNode methodNode;
+    private SourceUnit sourceUnit;
 
-    public void visitClass(ClassNode node, SourceUnit source) {
-        this.source = source;
-        super.visitClass(node);
+    @Override
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
     }
 
-    @Override
-    public void visitVariableExpression(VariableExpression ve) {
-        Variable v = ve.getAccessedVariable();
-        if (v instanceof DynamicVariable) {
-            if (!inPropertyExpression || inSpecialConstructorCall) addStaticVariableError(ve);
-        }
+    public void visitClass(ClassNode node, SourceUnit unit) {
+        sourceUnit = unit;
+        visitClass(node);
     }
 
     @Override
@@ -75,112 +61,43 @@ public class StaticVerifier extends ClassCodeVisitorSupport {
     @Override
     public void visitConstructorCallExpression(ConstructorCallExpression cce) {
         boolean oldIsSpecialConstructorCall = inSpecialConstructorCall;
-        inSpecialConstructorCall = cce.isSpecialCall();
+        inSpecialConstructorCall |= cce.isSpecialCall();
         super.visitConstructorCallExpression(cce);
         inSpecialConstructorCall = oldIsSpecialConstructorCall;
     }
 
     @Override
     public void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
-        MethodNode oldCurrentMethod = currentMethod;
-        currentMethod = node;
+        MethodNode oldMethodNode = methodNode;
+        methodNode = node;
         super.visitConstructorOrMethod(node, isConstructor);
         if (isConstructor) {
-            final Set<String> exceptions = new HashSet<String>();
-            for (final Parameter param : node.getParameters()) {
-                exceptions.add(param.getName());
+            for (Parameter param : node.getParameters()) {
                 if (param.hasInitialExpression()) {
-                    param.getInitialExpression().visit(new CodeVisitorSupport() {
-                        @Override
-                        public void visitVariableExpression(VariableExpression ve) {
-                            if (exceptions.contains(ve.getName())) return;
-                            if (ve.getAccessedVariable() instanceof DynamicVariable || !ve.isInStaticContext()) {
-                                addVariableError(ve);
-                            }
-                        }
-
-                        @Override
-                        public void visitMethodCallExpression(MethodCallExpression call) {
-                            Expression objectExpression = call.getObjectExpression();
-                            if (objectExpression instanceof VariableExpression) {
-                                VariableExpression ve = (VariableExpression) objectExpression;
-                                if (ve.isThisExpression()) {
-                                    addError("Can't access instance method '" + call.getMethodAsString() + "' for a constructor parameter default value", param);
-                                    return;
-                                }
-                            }
-                            super.visitMethodCallExpression(call);
-                        }
-
-                        @Override
-                        public void visitClosureExpression(ClosureExpression expression) {
-                            //skip contents, because of dynamic scope
-                        }
-                    });
-                }
-            }
-        }
-        currentMethod = oldCurrentMethod;
-    }
-
-    @Override
-    public void visitMethodCallExpression(MethodCallExpression mce) {
-        if (inSpecialConstructorCall && !isInnerClass(currentMethod.getDeclaringClass())) {
-            Expression objectExpression = mce.getObjectExpression();
-            if (objectExpression instanceof VariableExpression) {
-                VariableExpression ve = (VariableExpression) objectExpression;
-                if (ve.isThisExpression()) {
-                    addError("Can't access instance method '" + mce.getMethodAsString() + "' before the class is constructed", mce);
-                    return;
+                    // initial expression will be argument to special constructor call
+                    boolean oldIsSpecialConstructorCall = inSpecialConstructorCall;
+                    inSpecialConstructorCall = true;
+                    param.getInitialExpression().visit(this);
+                    inSpecialConstructorCall = oldIsSpecialConstructorCall;
                 }
             }
         }
-        super.visitMethodCallExpression(mce);
+        methodNode = oldMethodNode;
     }
 
     @Override
-    public void visitPropertyExpression(PropertyExpression pe) {
-        if (!inSpecialConstructorCall) checkStaticScope(pe);
-    }
-
-    @Override
-    protected SourceUnit getSourceUnit() {
-        return source;
-    }
-
-
-    private void checkStaticScope(PropertyExpression pe) {
-        if (inClosure) return;
-        for (Expression it = pe; it != null; it = ((PropertyExpression) it).getObjectExpression()) {
-            if (it instanceof PropertyExpression) continue;
-            if (it instanceof VariableExpression) {
-                addStaticVariableError((VariableExpression) it);
+    public void visitVariableExpression(VariableExpression ve) {
+        if (ve.getAccessedVariable() instanceof DynamicVariable
+                && (inSpecialConstructorCall || (!inClosure && ve.isInStaticContext()))) {
+            if (methodNode != null && methodNode.isStatic()) {
+                FieldNode fieldNode = getDeclaredOrInheritedField(methodNode.getDeclaringClass(), ve.getName());
+                if (fieldNode != null && fieldNode.isStatic()) return;
             }
-            return;
-        }
-    }
-
-    private void addStaticVariableError(VariableExpression ve) {
-        // closures are always dynamic
-        // propertyExpressions will handle the error a bit differently
-        if (!inSpecialConstructorCall && (inClosure || !ve.isInStaticContext())) return;
-        if (ve.isThisExpression() || ve.isSuperExpression()) return;
-        Variable v = ve.getAccessedVariable();
-        if (currentMethod != null && currentMethod.isStatic()) {
-            FieldNode fieldNode = getDeclaredOrInheritedField(currentMethod.getDeclaringClass(), ve.getName());
-            if (fieldNode != null && fieldNode.isStatic()) return;
+            addError("Apparent variable '" + ve.getName() + "' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:\n" +
+                    "You attempted to reference a variable in the binding or an instance variable from a static context.\n" +
+                    "You misspelled a classname or statically imported field. Please check the spelling.\n" +
+                    "You attempted to use a method '" + ve.getName() + "' but left out brackets in a place not allowed by the grammar.", ve);
         }
-        if (v != null && !(v instanceof DynamicVariable) && v.isInStaticContext()) return;
-        addVariableError(ve);
-    }
-
-    private void addVariableError(VariableExpression ve) {
-        addError("Apparent variable '" + ve.getName() + "' was found in a static scope but doesn't refer" +
-                " to a local variable, static field or class. Possible causes:\n" +
-                "You attempted to reference a variable in the binding or an instance variable from a static context.\n" +
-                "You misspelled a classname or statically imported field. Please check the spelling.\n" +
-                "You attempted to use a method '" + ve.getName() +
-                "' but left out brackets in a place not allowed by the grammar.", ve);
     }
 
     private static FieldNode getDeclaredOrInheritedField(ClassNode cn, String fieldName) {
@@ -188,7 +105,7 @@ public class StaticVerifier extends ClassCodeVisitorSupport {
         while (node != null) {
             FieldNode fn = node.getDeclaredField(fieldName);
             if (fn != null) return fn;
-            List<ClassNode> interfacesToCheck = new ArrayList<ClassNode>(Arrays.asList(node.getInterfaces()));
+            List<ClassNode> interfacesToCheck = new ArrayList<>(Arrays.asList(node.getInterfaces()));
             while (!interfacesToCheck.isEmpty()) {
                 ClassNode nextInterface = interfacesToCheck.remove(0);
                 fn = nextInterface.getDeclaredField(fieldName);
@@ -199,5 +116,4 @@ public class StaticVerifier extends ClassCodeVisitorSupport {
         }
         return null;
     }
-
 }
diff --git a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
index 394bb2d..71049ec 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -47,6 +47,7 @@ import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.classgen.FinalVariableAnalyzer;
 import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.classgen.VerifierCodeVisitor;
 import org.codehaus.groovy.control.ResolveVisitor;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.tools.Utilities;
@@ -55,6 +56,7 @@ import org.objectweb.asm.Opcodes;
 
 import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
+
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -181,8 +183,11 @@ public class JavaStubGenerator {
                 }
 
                 @Override
-                protected FinalVariableAnalyzer.VariableNotFinalCallback getFinalVariablesCallback() {
-                    return null;
+                public void visitConstructor(ConstructorNode node) {
+                    Statement stmt = node.getCode();
+                    if (stmt != null) {
+                        stmt.visit(new VerifierCodeVisitor(getClassNode()));
+                    }
                 }
 
                 @Override
@@ -243,6 +248,11 @@ public class JavaStubGenerator {
                 protected void addDefaultConstructor(ClassNode node) {
                     // not required for stub generation
                 }
+
+                @Override
+                protected FinalVariableAnalyzer.VariableNotFinalCallback getFinalVariablesCallback() {
+                    return null;
+                }
             };
             int origNumConstructors = classNode.getDeclaredConstructors().size();
             verifier.visitClass(classNode);
@@ -581,7 +591,7 @@ public class JavaStubGenerator {
             for (ClassNode stub:stubExceptions) {
                 if (stub.isDerivedFrom(superExc)) continue outer;
             }
-            // not found 
+            // not found
             return false;
         }
 
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index 966313b..6390075 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -18,12 +18,18 @@
  */
 package gls.innerClass
 
-import gls.CompilableTestSupport
+import groovy.transform.NotYetImplemented
+import org.codehaus.groovy.control.CompilationFailedException
+import org.junit.Test
 
-class InnerClassTest extends CompilableTestSupport {
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 
+final class InnerClassTest {
+
+    @Test
     void testTimerAIC() {
-        assertScript """
+        assertScript '''
             import java.util.concurrent.CountDownLatch
             import java.util.concurrent.TimeUnit
 
@@ -37,11 +43,12 @@ class InnerClassTest extends CompilableTestSupport {
             }, 0)
 
             assert called.await(10, TimeUnit.SECONDS)
-        """
+        '''
     }
 
+    @Test
     void testAICReferenceInClosure() {
-        assertScript """
+        assertScript '''
             def y = [true]
             def o = new Object() {
               def foo() {
@@ -52,21 +59,23 @@ class InnerClassTest extends CompilableTestSupport {
               }
             }
             o.foo()
-        """
+        '''
     }
 
+    @Test
     void testExtendsObjectAndAccessAFinalVariableInScope() {
-        assertScript """
+        assertScript '''
             final String objName = "My name is Guillaume"
 
             assert new Object() {
                 String toString() { objName }
             }.toString() == objName
-        """
+        '''
     }
 
+    @Test
     void testExtendsObjectAndReferenceAMethodParameterWithinAGString() {
-        assertScript """
+        assertScript '''
             Object makeObj0(String name) {
                 new Object() {
                     String toString() { "My name is \${name}" }
@@ -74,11 +83,12 @@ class InnerClassTest extends CompilableTestSupport {
             }
 
             assert makeObj0("Guillaume").toString() == "My name is Guillaume"
-        """
+        '''
     }
 
+    @Test
     void testExtendsObjectAndReferenceAGStringPropertyDependingOnAMethodParameter() {
-        assertScript """
+        assertScript '''
             Object makeObj1(String name) {
                  new Object() {
                     String objName = "My name is \${name}"
@@ -88,11 +98,12 @@ class InnerClassTest extends CompilableTestSupport {
             }
 
             assert makeObj1("Guillaume").toString() == "My name is Guillaume"
-        """
+        '''
     }
 
+    @Test
     void testUsageOfInitializerBlockWithinAnAIC() {
-        assertScript """
+        assertScript '''
             Object makeObj2(String name) {
                  new Object() {
                     String objName
@@ -108,11 +119,12 @@ class InnerClassTest extends CompilableTestSupport {
             }
 
             assert makeObj2("Guillaume").toString() == "My name is Guillaume"
-        """
+        '''
     }
 
+    @Test
     void testStaticInnerClass() {
-        assertScript """
+        assertScript '''
             import java.lang.reflect.Modifier
 
             class A {
@@ -123,41 +135,58 @@ class InnerClassTest extends CompilableTestSupport {
 
             def mods = A.B.modifiers
             assert Modifier.isPublic(mods)
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testStaticInnerClass2() {
+        assertScript '''
             class A {
                 static class B{}
             }
             assert A.declaredClasses.length==1
             assert A.declaredClasses[0]==A.B
-        """
+        '''
     }
 
-    void testNonStaticInnerClass_FAILS() {
-        if (notYetImplemented()) return
+    @Test
+    void testNonStaticInnerClass() {
+        assertScript '''
+            class A {
+                class B {
+                    final String foo = 'foo'
+                }
+            }
+            def b = new A.B(new A())
+            assert b.foo == 'foo'
+        '''
+    }
 
-        shouldNotCompile """
+    @Test @NotYetImplemented
+    void testNonStaticInnerClass2() {
+        shouldFail CompilationFailedException, '''
             class A {
                 class B {}
             }
-            def x = new A.B()
-        """
+            def x = new A.B() // requires reference to A
+        '''
     }
 
+    @Test
     void testAnonymousInnerClass() {
-        assertScript """
+        assertScript '''
             class Foo {}
 
             def x = new Foo(){
                 def bar() { 1 }
             }
             assert x.bar() == 1
-        """
+        '''
     }
 
+    @Test
     void testLocalVariable() {
-        assertScript """
+        assertScript '''
             class Foo {}
             final val = 2
             def x = new Foo() {
@@ -165,20 +194,22 @@ class InnerClassTest extends CompilableTestSupport {
             }
             assert x.bar() == val
             assert x.bar() == 2
-        """
+        '''
     }
 
+    @Test
     void testConstructor() {
-        shouldNotCompile """
+        shouldFail CompilationFailedException, '''
             class Foo {}
             def x = new Foo() {
                 Foo() {}
             }
-        """
+        '''
     }
 
+    @Test
     void testUsageOfOuterField() {
-        assertScript """
+        assertScript '''
             interface Run {
                 def run()
             }
@@ -198,9 +229,12 @@ class InnerClassTest extends CompilableTestSupport {
             assert foo.foo() == 1
             foo.x(2)
             assert foo.foo() == 2
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterField2() {
+        assertScript '''
             interface Run {
                 def run()
             }
@@ -219,9 +253,12 @@ class InnerClassTest extends CompilableTestSupport {
             assert Foo.foo() == 1
             Foo.x(2)
             assert Foo.foo() == 2
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterField3() {
+        assertScript '''
             interface X {
                 def m()
             }
@@ -240,9 +277,11 @@ class InnerClassTest extends CompilableTestSupport {
             }
             def a = new A()
             assert "pm" == a.foo()
-        """
+        '''
+    }
 
-        //GROOVY-6141
+    @Test // GROOVY-6141
+    void testUsageOfOuterField4() {
         assertScript '''
             class A {
                 def x = 1
@@ -271,45 +310,84 @@ class InnerClassTest extends CompilableTestSupport {
         '''
     }
 
-    void testUsageOfOuterFieldOverridden_FAILS() {
-        if (notYetImplemented()) return
+    @Test // GROOVY-9189
+    void testUsageOfOuterField5() {
+        assertScript '''
+            interface Run {
+                def run()
+            }
+            class Foo {
+                private static x = 1
+
+                static foo(def runner = new Run() {
+                    def run() { return x }
+                }) {
+                    runner.run()
+                }
+
+                static x(y) { x = y }
+            }
+            assert Foo.foo() == 1
+            Foo.x(2)
+            assert Foo.foo() == 2
+        '''
+    }
 
-        assertScript """
+    @Test // GROOVY-9168
+    void testUsageOfOuterField6() {
+        assertScript '''
+            class A {
+                //                  AIC in this position can use static properties:
+                A(Runnable action = new Runnable() { void run() { answer = 42 }}) {
+                    this.action = action
+                }
+                Runnable   action
+                static int answer
+            }
+
+            def a = new A()
+            a.action.run();
+            assert a.answer == 42
+        '''
+    }
+
+    @Test
+    void testUsageOfOuterFieldOverridden() {
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
                 private x = 1
+
                 def foo() {
-                    def runner = new Run(){
-                        def run() { return x }
+                    def runner = new Run() {
+                        def run() { return x } // <-- dynamic variable
                     }
                     runner.run()
                 }
-                void setX(y) { x=y }
+
+                void setX(val) { x = val }
             }
             class Bar extends Foo {
-                def x = "string"
+                def x = 'string' // hides 'foo.@x' and overrides 'foo.setX(val)'
             }
             def bar = new Bar()
-            assert bar.foo() == 1
-            bar.x(2)
-            assert bar.foo() == 2
-            bar.x = "new string"
-            assert bar.foo() == 2
-        """
-
-        //TODO: static part
-
+            assert bar.foo() == 'string'
+            bar.x = 'new string'
+            assert bar.foo() == 'new string'
+        '''
     }
 
+    @Test
     void testUsageOfOuterMethod() {
-        assertScript """
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private x(){1}
+                private x() { return 1 }
+
                 def foo() {
                     def runner = new Run(){
                         def run() { return x() }
@@ -319,14 +397,17 @@ class InnerClassTest extends CompilableTestSupport {
             }
             def foo = new Foo()
             assert foo.foo() == 1
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterMethod2() {
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private static x() {1}
+                private static x() { return 1 }
 
                 def foo() {
                     def runner = new Run() {
@@ -337,36 +418,99 @@ class InnerClassTest extends CompilableTestSupport {
             }
             def foo = new Foo()
             assert foo.foo() == 1
-        """
+        '''
+    }
+
+    @Test
+    void testUsageOfOuterMethod3() {
+        assertScript '''
+            interface Run {
+                def run()
+            }
+            class Foo {
+                private static x() { return 1 }
+
+                def foo(def runner = new Run() {
+                    def run() { return x() }
+                }) {
+                    runner.run()
+                }
+            }
+            def foo = new Foo()
+            assert foo.foo() == 1
+        '''
+    }
+
+    @Test // GROOVY-9189
+    void testUsageOfOuterMethod4() {
+        assertScript '''
+            interface Run {
+                def run()
+            }
+            class Foo {
+                private static x() { return 1 }
+
+                static def foo(def runner = new Run() {
+                    def run() { return x() }
+                }) {
+                    runner.run()
+                }
+            }
+            def foo = new Foo()
+            assert foo.foo() == 1
+        '''
+    }
+
+    @Test // GROOVY-9168
+    void testUsageOfOuterMethod5() {
+        assertScript '''
+            class A {
+                //                  AIC in this position can use static methods:
+                A(Runnable action = new Runnable() { void run() { setAnswer(42) }}) {
+                    this.action = action
+                }
+                Runnable action
+                static int answer
+            }
+
+            def a = new A()
+            a.action.run();
+            assert a.answer == 42
+        '''
     }
 
-    void testUsageOfOuterMethodoverridden() {
-        assertScript """
+    @Test
+    void testUsageOfOuterMethodOverridden() {
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private x(){1}
+                private x() { return 1 }
+
                 def foo() {
-                    def runner = new Run(){
+                    def runner = new Run() {
                         def run() { return x() }
                     }
                     runner.run()
                 }
             }
-            class Bar extends Foo{
-                def x() { 2 }
+            class Bar extends Foo {
+                def x() { return 2 }
             }
             def bar = new Bar()
             assert bar.foo() == 1
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterMethodOverridden2() {
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private static x() { 1 }
+                private static x() { return 1 }
 
                 static foo() {
                     def runner = new Run() {
@@ -376,13 +520,14 @@ class InnerClassTest extends CompilableTestSupport {
                 }
             }
             class Bar extends Foo {
-                static x() { 2 }
+                static x() { return 2 }
             }
             def bar = new Bar()
             assert bar.foo() == 1
-        """
+        '''
     }
 
+    @Test
     void testClassOutputOrdering() {
         // this does actually not do much, but before this
         // change the inner class was tried to be executed
@@ -391,16 +536,17 @@ class InnerClassTest extends CompilableTestSupport {
         // not. So if Foo$Bar is returned, asserScript will
         // fail. If Foo is returned, asserScript will not
         // fail.
-        assertScript """
+        assertScript '''
             class Foo {
                 static class Bar{}
                 static main(args){}
             }
-        """
+        '''
     }
 
+    @Test
     void testInnerClassDotThisUsage() {
-        assertScript """
+        assertScript '''
             class A{
                 int x = 0;
                 class B{
@@ -419,9 +565,12 @@ class InnerClassTest extends CompilableTestSupport {
             c.foo()
             assert a.x == 1
             assert b.y == 4
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testInnerClassDotThisUsage2() {
+        assertScript '''
             interface X {
                 def m()
             }
@@ -439,40 +588,45 @@ class InnerClassTest extends CompilableTestSupport {
             class B extends A {}
             def b = new B()
             assert b.foo() instanceof B
-        """
+        '''
     }
 
+    @Test
     void testImplicitThisPassingWithNamedArguments() {
         def oc = new MyOuterClass4028()
         assert oc.foo().propMap.size() == 2
     }
 
+    @Test
     void testThis0() {
-        assertScript """
-class A {
-   static def field = 10
-   void main (a) {
-     new C ().r ()
-   }
-
-   class C {
-      def r () {
-        4.times {
-          new B(it).u (it)
-        }
-      }
-   }
+        assertScript '''
+            class A {
+                static def field = 10
+                void main (a) {
+                    new C ().r ()
+                }
 
-   class B {
-     def s
-     B (s) { this.s = s}
-     def u (i) { println i + s + field }
-   }}"""
+                class C {
+                    def r () {
+                        4.times {
+                            new B(it).u (it)
+                        }
+                    }
+                }
+
+                class B {
+                    def s
+                    B (s) { this.s = s}
+                    def u (i) { println i + s + field }
+                }
+            }
+        '''
     }
 
+    @Test
     void testReferencedVariableInAIC() {
-        assertScript """
-            interface X{}
+        assertScript '''
+            interface X {}
 
             final double delta = 0.1
             (0 ..< 1).collect { n ->
@@ -482,9 +636,13 @@ class A {
                     }
                 }
             }
-        """
-        assertScript """
-            interface X{}
+        '''
+    }
+
+    @Test
+    void testReferencedVariableInAIC2() {
+        assertScript '''
+            interface X {}
 
             final double delta1 = 0.1
             final double delta2 = 0.1
@@ -495,10 +653,10 @@ class A {
                     }
                 }
             }
-        """
+        '''
     }
 
-    // GROOVY-5989
+    @Test // GROOVY-5989
     void testReferenceToOuterClassNestedInterface() {
         assertScript '''
             interface Koo { class Inner { } }
@@ -511,39 +669,20 @@ class A {
         '''
     }
 
-    // GROOVY-5679, GROOVY-5681
+    @Test // GROOVY-5679, GROOVY-5681
     void testEnclosingMethodIsSet() {
         assertScript '''
             import groovy.transform.ASTTest
-            import org.codehaus.groovy.ast.InnerClassNode
-            import org.codehaus.groovy.ast.expr.ConstructorCallExpression
+            import org.codehaus.groovy.ast.expr.*
             import static org.codehaus.groovy.classgen.Verifier.*
             import static org.codehaus.groovy.control.CompilePhase.*
 
             class A {
-                int x
-
-                /*@ASTTest(phase=SEMANTIC_ANALYSIS, value={
-                    def cce = lookup('inner')[0].expression
-                    def icn = cce.type
-                    assert icn instanceof InnerClassNode
-                    assert icn.enclosingMethod == node
-                })
-                A() { inner: new Runnable() { void run() {} } }
-
-                @ASTTest(phase=SEMANTIC_ANALYSIS, value={
-                    def cce = lookup('inner')[0].expression
-                    def icn = cce.type
-                    assert icn instanceof InnerClassNode
-                    assert icn.enclosingMethod == node
-                })
-                void foo() { inner: new Runnable() { void run() {} } }*/
-
                 @ASTTest(phase=CLASS_GENERATION, value={
                     def initialExpression = node.parameters[0].getNodeMetaData(INITIAL_EXPRESSION)
                     assert initialExpression instanceof ConstructorCallExpression
                     def icn = initialExpression.type
-                    assert icn instanceof InnerClassNode
+                    assert icn instanceof org.codehaus.groovy.ast.InnerClassNode
                     assert icn.enclosingMethod != null
                     assert icn.enclosingMethod.name == 'bar'
                     assert icn.enclosingMethod.parameters.length == 0 // ensure the enclosing method is bar(), not bar(Object)
@@ -551,6 +690,7 @@ class A {
                 void bar(action = new Runnable() { void run() { x = 123 }}) {
                     action.run()
                 }
+                int x
             }
             def a = new A()
             a.bar()
@@ -558,7 +698,7 @@ class A {
         '''
     }
 
-    // GROOVY-5681, GROOVY-9151
+    @Test // GROOVY-5681, GROOVY-9151
     void testEnclosingMethodIsSet2() {
         assertScript '''
             import groovy.transform.ASTTest
@@ -584,7 +724,7 @@ class A {
         '''
     }
 
-    // GROOVY-5681, GROOVY-9151
+    @Test // GROOVY-5681, GROOVY-9151
     void testEnclosingMethodIsSet3() {
         assertScript '''
             import groovy.transform.ASTTest
@@ -624,7 +764,7 @@ class A {
         '''
     }
 
-    // GROOVY-4896, GROOVY-6810
+    @Test // GROOVY-6810
     void testThisReferenceForAICInOpenBlock() {
         assertScript '''
             import java.security.AccessController
@@ -656,7 +796,10 @@ class A {
             def t = new Test()
             injectVariables(t, ['p': 'q'])
         '''
+    }
 
+    @Test // GROOVY-4896
+    void testThisReferenceForAICInOpenBlock2() {
         assertScript '''
             def doSomethingUsingLocal(){
                 logExceptions {
@@ -720,8 +863,8 @@ class A {
         '''
     }
 
-    // GROOVY-5582
-    void testAICextendingAbstractInnerClass() {
+    @Test // GROOVY-5582
+    void testAICExtendingAbstractInnerClass() {
         assertScript '''
             class Outer {
                 int outer() { 1 }
@@ -739,7 +882,7 @@ class A {
         '''
     }
 
-    // GROOVY-6831
+    @Test // GROOVY-6831
     void testNestedPropertyHandling() {
         assertScript '''
             class Outer {
@@ -762,7 +905,7 @@ class A {
         '''
     }
 
-    // GROOVY-7312
+    @Test // GROOVY-7312
     void testInnerClassOfInterfaceIsStatic() {
         assertScript '''
             import java.lang.reflect.Modifier
@@ -774,7 +917,7 @@ class A {
         '''
     }
 
-    // GROOVY-7312
+    @Test // GROOVY-7312
     void testInnerClassOfInterfaceIsStatic2() {
         assertScript '''
             import java.lang.reflect.Modifier
@@ -792,7 +935,7 @@ class A {
         '''
     }
 
-    // GROOVY-8914
+    @Test // GROOVY-8914
     void testNestedClassInheritingFromNestedClass() {
         // control
         assert new Outer8914.Nested()
@@ -805,9 +948,9 @@ class A {
         '''
     }
 
-    // GROOVY-6809
-    void _FIXME_testReferenceToUninitializedThis() {
-        assertScript '''
+    @Test // GROOVY-6809
+    void testReferenceToUninitializedThis() {
+        def err = shouldFail '''
             class Test {
                 static main(args) {
                     def a = new A()
@@ -818,22 +961,19 @@ class A {
                         def b = new B()
                     }
 
-                    void sayA() {
-                        println 'saying A'
-                    }
-
                     class B extends A {
                         B() {
-                            super(A.this) // does not exist
-                            sayA()
+                            super(A.this)
                         }
                     }
                 }
             }
         '''
+
+        assert err =~ / Could not find matching constructor for: Test.A\(Test.A\)/
     }
 
-    // GROOVY-6809
+    @Test // GROOVY-6809
     void testReferenceToUninitializedThis2() {
         assertScript '''
             class A {
@@ -853,7 +993,7 @@ class A {
         '''
     }
 
-    // GROOVY-6809
+    @Test // GROOVY-6809
     void testReferenceToUninitializedThis3() {
         assertScript '''
             class A {
@@ -870,39 +1010,27 @@ class A {
         '''
     }
 
-    // GROOVY-7609
-    void _FIXME_testReferenceToUninitializedThis4() {
-        assertScript '''
-            class Login {
-                Login() {
-                    def navBar = new LoginNavigationBar()
-                }
-
-                class LoginNavigationBar {
-                    ExploreDestinationsDropdown exploreDestinationsDropdown
-
-                    LoginNavigationBar() {
-                        exploreDestinationsDropdown = new ExploreDestinationsDropdown()
-                    }
-
-                    class ExploreDestinationsDropdown /*extends NavigationBarDropdown<ExploreDestinationsDropdown>*/ {
-                        ExploreDestinationsDropdown() {
-                            //super(Login.this.sw, 0)
-                            Login.this.sw
-                        }
-                    }
-                }
-
-                static main(args) {
-                    new Login()
-                }
+    @Test // GROOVY-9168
+    void testReferenceToUninitializedThis4() {
+        def err = shouldFail '''
+            class Outer {
+              class Inner {
+              }
+              Outer(Inner inner) {
+              }
+              Outer() {
+                  this(new Inner())
+              }
             }
+            new Outer()
         '''
+
+        assert err =~ / Cannot reference 'this' before supertype constructor has been called. /
     }
 
-    // GROOVY-9168
-    void _FIXME_testReferenceToUninitializedThis5() {
-        assertScript '''
+    @Test // GROOVY-9168
+    void testReferenceToUninitializedThis5() {
+        def err = shouldFail '''
             class Outer {
               class Inner {
               }
@@ -911,9 +1039,11 @@ class A {
             }
             new Outer()
         '''
+
+        assert err =~ / Cannot reference 'this' before supertype constructor has been called. /
     }
 
-    // GROOVY-9168
+    @Test // GROOVY-9168
     void testReferenceToUninitializedThis6() {
         assertScript '''
             import groovy.transform.ASTTest
@@ -941,45 +1071,10 @@ class A {
             assert a.action.call() == 42
         '''
     }
-
-    // GROOVY-9168
-    void _FIXME_testReferenceToUninitializedThis7() {
-        assertScript '''
-            class A {
-                //                  AIC in this position can use static properties:
-                A(Runnable action = new Runnable() { void run() { answer = 42 }}) {
-                    this.action = action
-                }
-                Runnable   action
-                static int answer
-            }
-
-            def a = new A()
-            a.action.run();
-            assert a.answer == 42
-        '''
-    }
-
-    // GROOVY-9168
-    void _FIXME_testReferenceToUninitializedThis8() {
-        assertScript '''
-            class A {
-                //                  AIC in this position can use static methods:
-                A(Runnable action = new Runnable() { void run() { setAnswer(42) }}) {
-                    this.action = action
-                }
-                Runnable action
-                protected static int answer
-                static void setAnswer(int value) { answer = value }
-            }
-
-            def a = new A()
-            a.action.run();
-            assert a.answer == 42
-        '''
-    }
 }
 
+//------------------------------------------------------------------------------
+
 class Parent8914 {
     static class Nested {}
 }
diff --git a/src/test/groovy/bugs/ConstructorParameterBug.groovy b/src/test/groovy/bugs/ConstructorParameterBug.groovy
index c881b96..e73e1ee 100644
--- a/src/test/groovy/bugs/ConstructorParameterBug.groovy
+++ b/src/test/groovy/bugs/ConstructorParameterBug.groovy
@@ -18,37 +18,42 @@
  */
 package groovy.bugs
 
-import gls.CompilableTestSupport
+import org.junit.Test
 
-class ConstructorParameterBug extends CompilableTestSupport {
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 
+final class ConstructorParameterBug {
+
+    @Test
     void testParamWithDefaultCallingStaticMethod() {
         assertScript '''
-        class StaticDefault {
-            def name
-            StaticDefault(name = baz()) {
-                this.name = name
-            }
-            private static baz() {
-                'baz'
+            class StaticDefault {
+                def name
+                StaticDefault(name = baz()) {
+                    this.name = name
+                }
+                private static baz() {
+                    'baz'
+                }
             }
-        }
-        assert 'baz' == new StaticDefault().name
+            assert 'baz' == new StaticDefault().name
         '''
     }
 
+    @Test
     void testParamWithDefaultCallingInstanceMethod() {
-        def msg = shouldFail '''
-        class InstanceDefault {
-            def name
-            InstanceDefault(name = baz()) {
-                this.name = name
-            }
-            private baz() {
-                'baz'
+        def err = shouldFail '''
+            class InstanceDefault {
+                def name
+                InstanceDefault(name = baz()) {
+                    this.name = name
+                }
+                private baz() {
+                    'baz'
+                }
             }
-        }
         '''
-        assert msg.contains("Can't access instance method 'baz' for a constructor parameter default value")
+        assert err =~ / Cannot reference 'baz' before supertype constructor has been called. /
     }
 }
diff --git a/src/test/groovy/bugs/ConstructorThisCallBug.groovy b/src/test/groovy/bugs/ConstructorThisCallBug.groovy
index e6faf9e..bf48d44 100644
--- a/src/test/groovy/bugs/ConstructorThisCallBug.groovy
+++ b/src/test/groovy/bugs/ConstructorThisCallBug.groovy
@@ -18,32 +18,14 @@
  */
 package groovy.bugs
 
-class ConstructorThisCallBug extends GroovyTestCase {
-    // GROOVY-7014
-    void testThisCallingInstanceMethod() {
-        def msg = shouldFail '''
-            class Base {
-                String getData() { return "ABCD" }
-                Base() { this(getData()) }
-                Base(String arg) {}
-            }
-        '''
-        assert msg.contains("Can't access instance method 'getData' before the class is constructed")
-    }
+import org.junit.Test
 
-    void testNestedClassThisCallingInstanceMethod() {
-        def msg = shouldFail '''
-            class Base {
-                static class Nested {
-                    String getData() { return "ABCD" }
-                    Nested() { this(getData()) }
-                    Nested(String arg) {}
-                }
-            }
-        '''
-        assert msg.contains("Can't access instance method 'getData' before the class is constructed")
-    }
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 
+final class ConstructorThisCallBug {
+
+    @Test
     void testThisCallingStaticMethod() {
         assertScript '''
             class Base {
@@ -57,7 +39,8 @@ class ConstructorThisCallBug extends GroovyTestCase {
         '''
     }
 
-    void testNestedThisCallingStaticMethod() {
+    @Test
+    void testNestedClassThisCallingStaticMethod() {
         assertScript '''
             class Base {
                 static class Nested {
@@ -72,7 +55,8 @@ class ConstructorThisCallBug extends GroovyTestCase {
         '''
     }
 
-    void testInnerClassSuperCallingInstanceMethod() {
+    @Test
+    void testNestedClassSuperCallingStaticMethod() {
         assertScript '''
             class Parent {
                 String str
@@ -82,11 +66,10 @@ class ConstructorThisCallBug extends GroovyTestCase {
                 static String a
 
                 private class Inner extends Parent {
-                   Inner() { super(myA()) }
+                   Inner() { super(getA()) }
                 }
 
                 String test() { new Inner().str }
-                String myA() { a }
             }
             def o = new Outer()
             Outer.a = 'ok'
@@ -94,8 +77,37 @@ class ConstructorThisCallBug extends GroovyTestCase {
         '''
     }
 
-    void testInnerClassSuperCallingStaticProperty() {
-        assertScript '''
+    //
+
+    @Test // GROOVY-7014
+    void testThisCallingInstanceMethod() {
+        def err = shouldFail '''
+            class Base {
+                String getData() { return "ABCD" }
+                Base() { this(getData()) }
+                Base(String arg) {}
+            }
+        '''
+        assert err =~ / Cannot reference 'getData' before supertype constructor has been called. /
+    }
+
+    @Test
+    void testNestedClassThisCallingInstanceMethod() {
+        def err = shouldFail '''
+            class Base {
+                static class Nested {
+                    String getData() { return "ABCD" }
+                    Nested() { this(getData()) }
+                    Nested(String arg) {}
+                }
+            }
+        '''
+        assert err =~ / Cannot reference 'getData' before supertype constructor has been called. /
+    }
+
+    @Test
+    void testNestedClassSuperCallingInstanceMethod() {
+        def err = shouldFail '''
             class Parent {
                 String str
                 Parent(String s) { str = s }
@@ -104,18 +116,22 @@ class ConstructorThisCallBug extends GroovyTestCase {
                 static String a
 
                 private class Inner extends Parent {
-                   Inner() { super(getA()) }
+                   Inner() { super(myA()) }
                 }
 
                 String test() { new Inner().str }
+                String myA() { a }
             }
             def o = new Outer()
             Outer.a = 'ok'
             assert o.test() == 'ok'
         '''
+        assert err =~ / Cannot reference 'myA' before supertype constructor has been called. /
     }
 
-    // GROOVY-994
+    //
+
+    @Test // GROOVY-994
     void testCallA() {
         assert new ConstructorCallA("foo").toString() == 'foo'
         assert new ConstructorCallA(9).toString() == '81'
diff --git a/src/test/groovy/bugs/Groovy5259Bug.groovy b/src/test/groovy/bugs/Groovy5259.groovy
similarity index 92%
rename from src/test/groovy/bugs/Groovy5259Bug.groovy
rename to src/test/groovy/bugs/Groovy5259.groovy
index 267fe2f..1b4bc28 100644
--- a/src/test/groovy/bugs/Groovy5259Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5259.groovy
@@ -18,9 +18,15 @@
  */
 package groovy.bugs
 
-class Groovy5259Bug extends GroovyTestCase {
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
+
+final class Groovy5259 {
+
+    @Test
     void testInnerClassAccessingOuterClassConstant() {
-        // using a script because the bug is a compiler error
         assertScript '''
             class InnerAccessOuter {
                 static final String OUTER_CONSTANT = 'Constant Value'
@@ -41,13 +47,11 @@ class Groovy5259Bug extends GroovyTestCase {
             }
             new InnerAccessOuter().testInnerClassAccessOuter()
         '''
-
     }
 
+    @Test
     void testInnerClassWithWrongCallToSuperAccessingOuterClassConstant() {
-        // using a script because the bug is a compiler error
-        shouldFail {
-            assertScript '''
+        shouldFail '''
             class InnerAccessOuter {
                 protected static final String OUTER_CONSTANT = 'Constant Value'
 
@@ -69,11 +73,10 @@ class Groovy5259Bug extends GroovyTestCase {
             }
             new InnerAccessOuter().testInnerClassAccessOuter()
         '''
-        }
     }
 
+    @Test
     void testInnerClassWithSuperClassAccessingOuterClassConstant() {
-        // using a script because the bug is a compiler error
         assertScript '''
             class Base {
                 Base(String str) {}
@@ -96,11 +99,10 @@ class Groovy5259Bug extends GroovyTestCase {
             }
             new InnerAccessOuter().testInnerClassAccessOuter()
         '''
-
     }
 
+    @Test
     void testInnerClassWithSuperClassAccessingSuperOuterClassConstant() {
-        // using a script because the bug is a compiler error
         assertScript '''
             class Base {
                 Base(String str) {}
@@ -125,6 +127,5 @@ class Groovy5259Bug extends GroovyTestCase {
             }
             new InnerAccessOuter().testInnerClassAccessOuter()
         '''
-
     }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index 062054b..9ede077 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1198,83 +1198,83 @@ println someInt
 
     void testAccessOuterClassMethodFromInnerClassConstructor() {
         assertScript '''
-    class Parent {
-        String str
-        Parent(String s) { str = s }
-    }
-    class Outer {
-        String a
+            class Parent {
+                String str
+                Parent(String s) { str = s }
+            }
+            class Outer {
+                String a
 
-        private class Inner extends Parent {
-           Inner() { super(getA()) }
-        }
+                private class Inner extends Parent {
+                   Inner() { super(getA()) }
+                }
 
-        String test() { new Inner().str }
-    }
-    def o = new Outer(a:'ok')
-    assert o.test() == 'ok'
-    '''
+                String test() { new Inner().str }
+            }
+            def o = new Outer(a:'ok')
+            assert o.test() == 'ok'
+        '''
     }
 
     void testAccessOuterClassMethodFromInnerClassConstructorUsingExplicitOuterThis() {
         assertScript '''
-    class Parent {
-        String str
-        Parent(String s) { str = s }
-    }
-    class Outer {
-        String a
+            class Parent {
+                String str
+                Parent(String s) { str = s }
+            }
+            class Outer {
+                String a
 
-        private class Inner extends Parent {
-           Inner() { super(Outer.this.getA()) }
-        }
+                private class Inner extends Parent {
+                   Inner() { super(Outer.this.getA()) }
+                }
 
-        String test() { new Inner().str }
-    }
-    def o = new Outer(a:'ok')
-    assert o.test() == 'ok'
-    '''
+                String test() { new Inner().str }
+            }
+            def o = new Outer(a:'ok')
+            assert o.test() == 'ok'
+        '''
     }
 
     void testAccessOuterClassMethodFromInnerClassConstructorUsingExplicitOuterThisAndProperty() {
         assertScript '''
-    class Parent {
-        String str
-        Parent(String s) { str = s }
-    }
-    class Outer {
-        String a
+            class Parent {
+                String str
+                Parent(String s) { str = s }
+            }
+            class Outer {
+                String a
 
-        private class Inner extends Parent {
-           Inner() { super(Outer.this.a) }
-        }
+                private class Inner extends Parent {
+                   Inner() { super(Outer.this.a) }
+                }
 
-        String test() { new Inner().str }
-    }
-    def o = new Outer(a:'ok')
-    assert o.test() == 'ok'
-    '''
+                String test() { new Inner().str }
+            }
+            def o = new Outer(a:'ok')
+            assert o.test() == 'ok'
+        '''
     }
 
     void testAccessOuterClassStaticMethodFromInnerClassConstructor() {
         assertScript '''
-    class Parent {
-        String str
-        Parent(String s) { str = s }
-    }
-    class Outer {
-        static String a
+            class Parent {
+                String str
+                Parent(String s) { str = s }
+            }
+            class Outer {
+                static String a
 
-        private class Inner extends Parent {
-           Inner() { super(getA()) }
-        }
+                private class Inner extends Parent {
+                   Inner() { super(getA()) }
+                }
 
-        String test() { new Inner().str }
-    }
-    def o = new Outer()
-    Outer.a = 'ok'
-    assert o.test() == 'ok'
-    '''
+                String test() { new Inner().str }
+            }
+            def o = new Outer()
+            Outer.a = 'ok'
+            assert o.test() == 'ok'
+        '''
     }
 
     void testStaticMethodFromInnerClassConstructor() {


Mime
View raw message