http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java 
b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
new file mode 100644
index 0000000..a439197
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -0,0 +1,610 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control;
+
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.NamedArgumentListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.syntax.Types;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static 
org.apache.groovy.ast.tools.ClassNodeUtils.getPropNameForAccessor;
+import static 
org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticMethod;
+import static 
org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticProperty;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.hasStaticProperty;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.isInnerClass;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.isValidAccessorName;
+import static org.codehaus.groovy.runtime.MetaClassHelper.capitalize;
+
+/**
+ * Visitor to resolve constants and method calls from static Imports
+ */
+public class StaticImportVisitor extends ClassCodeExpressionTransformer {
+    private ClassNode currentClass;
+    private MethodNode currentMethod;
+    private SourceUnit source;
+    private boolean inSpecialConstructorCall;
+    private boolean inClosure;
+    private boolean inPropertyExpression;
+    private Expression foundConstant;
+    private Expression foundArgs;
+    private boolean inAnnotation;
+    private boolean inLeftExpression;
+
+    public void visitClass(ClassNode node, SourceUnit source) {
+        this.currentClass = node;
+        this.source = source;
+        super.visitClass(node);
+    }
+
+    @Override
+    protected void visitConstructorOrMethod(MethodNode node, boolean 
isConstructor) {
+        this.currentMethod = node;
+        super.visitConstructorOrMethod(node, isConstructor);
+        this.currentMethod = null;
+    }
+
+    @Override
+    public void visitAnnotations(AnnotatedNode node) {
+        boolean oldInAnnotation = inAnnotation;
+        inAnnotation = true;
+        super.visitAnnotations(node);
+        inAnnotation = oldInAnnotation;
+    }
+
+    public Expression transform(Expression exp) {
+        if (exp == null) return null;
+        if (exp.getClass() == VariableExpression.class) {
+            return transformVariableExpression((VariableExpression) exp);
+        }
+        if (exp.getClass() == BinaryExpression.class) {
+            return transformBinaryExpression((BinaryExpression) exp);
+        }
+        if (exp.getClass() == PropertyExpression.class) {
+            return transformPropertyExpression((PropertyExpression) exp);
+        }
+        if (exp.getClass() == MethodCallExpression.class) {
+            return transformMethodCallExpression((MethodCallExpression) exp);
+        }
+        if (exp.getClass() == ClosureExpression.class) {
+            return transformClosureExpression((ClosureExpression) exp);
+        }
+        if (exp.getClass() == ConstructorCallExpression.class) {
+            return 
transformConstructorCallExpression((ConstructorCallExpression) exp);
+        }
+        if (exp.getClass() == ArgumentListExpression.class) {
+            Expression result = exp.transformExpression(this);
+            if (inPropertyExpression) {
+                foundArgs = result;
+            }
+            return result;
+        }
+        if (exp instanceof ConstantExpression) {
+            Expression result = exp.transformExpression(this);
+            if (inPropertyExpression) {
+                foundConstant = result;
+            }
+            if (inAnnotation && exp instanceof AnnotationConstantExpression) {
+                ConstantExpression ce = (ConstantExpression) result;
+                if (ce.getValue() instanceof AnnotationNode) {
+                    // replicate a little bit of AnnotationVisitor here
+                    // because we can't wait until later to do this
+                    AnnotationNode an = (AnnotationNode) ce.getValue();
+                    Map<String, Expression> attributes = an.getMembers();
+                    for (Map.Entry<String, Expression> entry : 
attributes.entrySet()) {
+                        Expression attrExpr = transform(entry.getValue());
+                        entry.setValue(attrExpr);
+                    }
+
+                }
+            }
+            return result;
+        }
+        return exp.transformExpression(this);
+    }
+
+    // if you have a Bar class with a static foo property, and this:
+    //   import static Bar.foo as baz
+    // then this constructor (not normal usage of statics):
+    //   new Bar(baz:1)
+    // will become:
+    //   new Bar(foo:1)
+
+    private Expression transformMapEntryExpression(MapEntryExpression me, 
ClassNode constructorCallType) {
+        Expression key = me.getKeyExpression();
+        Expression value = me.getValueExpression();
+        ModuleNode module = currentClass.getModule();
+        if (module != null && key instanceof ConstantExpression) {
+            Map<String, ImportNode> importNodes = module.getStaticImports();
+            if (importNodes.containsKey(key.getText())) {
+                ImportNode importNode = importNodes.get(key.getText());
+                if (importNode.getType().equals(constructorCallType)) {
+                    String newKey = importNode.getFieldName();
+                    return new MapEntryExpression(new 
ConstantExpression(newKey), value.transformExpression(this));
+                }
+            }
+        }
+        return me;
+    }
+
+    protected Expression transformBinaryExpression(BinaryExpression be) {
+        int type = be.getOperation().getType();
+        boolean oldInLeftExpression;
+        Expression right = transform(be.getRightExpression());
+        be.setRightExpression(right);
+        Expression left;
+        if (type == Types.EQUAL && be.getLeftExpression() instanceof 
VariableExpression) {
+            oldInLeftExpression = inLeftExpression;
+            inLeftExpression = true;
+            left = transform(be.getLeftExpression());
+            inLeftExpression = oldInLeftExpression;
+            if (left instanceof StaticMethodCallExpression) {
+                StaticMethodCallExpression smce = (StaticMethodCallExpression) 
left;
+                StaticMethodCallExpression result = new 
StaticMethodCallExpression(smce.getOwnerType(), smce.getMethod(), right);
+                setSourcePosition(result, be);
+                return result;
+            }
+        } else {
+            left = transform(be.getLeftExpression());
+        }
+        be.setLeftExpression(left);
+        return be;
+    }
+
+    protected Expression transformVariableExpression(VariableExpression ve) {
+        Variable v = ve.getAccessedVariable();
+        if (v != null && v instanceof DynamicVariable) {
+            Expression result = 
findStaticFieldOrPropAccessorImportFromModule(v.getName());
+            if (result != null) {
+                setSourcePosition(result, ve);
+                if (inAnnotation) {
+                    result = transformInlineConstants(result);
+                }
+                return result;
+            }
+        }
+        return ve;
+    }
+
+    /**
+     * Set the source position of toSet including its property expression if 
it has one.
+     *
+     * @param toSet resulting node
+     * @param origNode original node
+     */
+    private static void setSourcePosition(Expression toSet, Expression 
origNode) {
+        toSet.setSourcePosition(origNode);
+        if (toSet instanceof PropertyExpression) {
+            ((PropertyExpression) 
toSet).getProperty().setSourcePosition(origNode);
+        }
+    }
+
+    // resolve constant-looking expressions statically (do here as gets 
transformed away later)
+
+    private Expression transformInlineConstants(Expression exp) {
+        if (exp instanceof PropertyExpression) {
+            PropertyExpression pe = (PropertyExpression) exp;
+            if (pe.getObjectExpression() instanceof ClassExpression) {
+                ClassExpression ce = (ClassExpression) 
pe.getObjectExpression();
+                ClassNode type = ce.getType();
+                if (type.isEnum()) return exp;
+                Expression constant = findConstant(getField(type, 
pe.getPropertyAsString()));
+                if (constant != null) return constant;
+            }
+        } else if (exp instanceof ListExpression) {
+            ListExpression le = (ListExpression) exp;
+            ListExpression result = new ListExpression();
+            for (Expression e : le.getExpressions()) {
+                result.addExpression(transformInlineConstants(e));
+            }
+            return result;
+        }
+
+        return exp;
+    }
+
+    private static Expression findConstant(FieldNode fn) {
+        if (fn != null && !fn.isEnum() && fn.isStatic() && fn.isFinal()) {
+            if (fn.getInitialValueExpression() instanceof ConstantExpression) {
+                return fn.getInitialValueExpression();
+            }
+        }
+        return null;
+    }
+
+    protected Expression transformMethodCallExpression(MethodCallExpression 
mce) {
+        Expression args = transform(mce.getArguments());
+        Expression method = transform(mce.getMethod());
+        Expression object = transform(mce.getObjectExpression());
+        boolean isExplicitThisOrSuper = false;
+        boolean isExplicitSuper = false;
+        if (object instanceof VariableExpression) {
+            VariableExpression ve = (VariableExpression) object;
+            isExplicitThisOrSuper = !mce.isImplicitThis() && 
(ve.isThisExpression() || ve.isSuperExpression());
+            isExplicitSuper = ve.isSuperExpression();
+        }
+
+        if (mce.isImplicitThis() || isExplicitThisOrSuper) {
+            if (mce.isImplicitThis()) {
+                Expression ret = findStaticMethodImportFromModule(method, 
args);
+                if (ret != null) {
+                    setSourcePosition(ret, mce);
+                    return ret;
+                }
+                if (method instanceof ConstantExpression && !inLeftExpression) 
{
+                    // could be a closure field
+                    String methodName = (String) ((ConstantExpression) 
method).getValue();
+                    ret = 
findStaticFieldOrPropAccessorImportFromModule(methodName);
+                    if (ret != null) {
+                        ret = new MethodCallExpression(ret, "call", args);
+                        setSourcePosition(ret, mce);
+                        return ret;
+                    }
+                }
+            } else if (currentMethod!=null && currentMethod.isStatic() && 
isExplicitSuper) {
+                MethodCallExpression ret = new MethodCallExpression(new 
ClassExpression(currentClass.getSuperClass()), method, args);
+                setSourcePosition(ret, mce);
+                return ret;
+            }
+
+            if (method instanceof ConstantExpression) {
+                ConstantExpression ce = (ConstantExpression) method;
+                Object value = ce.getValue();
+                if (value instanceof String) {
+                    boolean foundInstanceMethod = false;
+                    String methodName = (String) value;
+                    boolean inInnerClass = isInnerClass(currentClass);
+                    if (currentMethod != null && !currentMethod.isStatic()) {
+                        if (currentClass.hasPossibleMethod(methodName, args)) {
+                            foundInstanceMethod = true;
+                        }
+                    }
+                    boolean lookForPossibleStaticMethod = 
!methodName.equals("call");
+                    lookForPossibleStaticMethod &= !foundInstanceMethod;
+                    lookForPossibleStaticMethod |= inSpecialConstructorCall;
+                    lookForPossibleStaticMethod &= !inInnerClass;
+                    if (!inClosure && lookForPossibleStaticMethod &&
+                            (hasPossibleStaticMethod(currentClass, methodName, 
args, true))
+                            || hasPossibleStaticProperty(currentClass, 
methodName)) {
+                        StaticMethodCallExpression smce = new 
StaticMethodCallExpression(currentClass, methodName, args);
+                        setSourcePosition(smce, mce);
+                        return smce;
+                    }
+                    if (!inClosure && inInnerClass && inSpecialConstructorCall 
&& mce.isImplicitThis() && !foundInstanceMethod) {
+                        if 
(currentClass.getOuterClass().hasPossibleMethod(methodName, args)) {
+                            object = new PropertyExpression(new 
ClassExpression(currentClass.getOuterClass()), new ConstantExpression("this"));
+                        } else if 
(hasPossibleStaticMethod(currentClass.getOuterClass(), methodName, args, true)
+                                || 
hasPossibleStaticProperty(currentClass.getOuterClass(), methodName)) {
+                            StaticMethodCallExpression smce = new 
StaticMethodCallExpression(currentClass.getOuterClass(), methodName, args);
+                            setSourcePosition(smce, mce);
+                            return smce;
+                        }
+                    }
+                }
+            }
+        }
+
+        MethodCallExpression result = new MethodCallExpression(object, method, 
args);
+        result.setSafe(mce.isSafe());
+        result.setImplicitThis(mce.isImplicitThis());
+        result.setSpreadSafe(mce.isSpreadSafe());
+        result.setMethodTarget(mce.getMethodTarget());
+        // GROOVY-6757
+        result.setGenericsTypes(mce.getGenericsTypes());
+        setSourcePosition(result, mce);
+        return result;
+    }
+
+    protected Expression 
transformConstructorCallExpression(ConstructorCallExpression cce) {
+        inSpecialConstructorCall = cce.isSpecialCall();
+        Expression expression = cce.getArguments();
+        if (expression instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) expression;
+            if (tuple.getExpressions().size() == 1) {
+                expression = tuple.getExpression(0);
+                if (expression instanceof NamedArgumentListExpression) {
+                    NamedArgumentListExpression namedArgs = 
(NamedArgumentListExpression) expression;
+                    List<MapEntryExpression> entryExpressions = 
namedArgs.getMapEntryExpressions();
+                    for (int i = 0; i < entryExpressions.size(); i++) {
+                        entryExpressions.set(i, (MapEntryExpression) 
transformMapEntryExpression(entryExpressions.get(i), cce.getType()));
+                    }
+                }
+            }
+        }
+        Expression ret = cce.transformExpression(this);
+        inSpecialConstructorCall = false;
+        return ret;
+    }
+
+    protected Expression transformClosureExpression(ClosureExpression ce) {
+        boolean oldInClosure = inClosure;
+        inClosure = true;
+        if (ce.getParameters() != null) {
+            for (Parameter p : ce.getParameters()) {
+                if (p.hasInitialExpression()) {
+                    
p.setInitialExpression(transform(p.getInitialExpression()));
+                }
+            }
+        }
+        Statement code = ce.getCode();
+        if (code != null) code.visit(this);
+        inClosure = oldInClosure;
+        return ce;
+    }
+
+    protected Expression transformPropertyExpression(PropertyExpression pe) {
+        if (currentMethod!=null && currentMethod.isStatic()
+                && pe.getObjectExpression() instanceof VariableExpression
+                && ((VariableExpression) 
pe.getObjectExpression()).isSuperExpression()) {
+            PropertyExpression pexp = new PropertyExpression(
+                    new ClassExpression(currentClass.getSuperClass()),
+                    transform(pe.getProperty())
+            );
+            pexp.setSourcePosition(pe);
+            return pexp;
+        }
+        boolean oldInPropertyExpression = inPropertyExpression;
+        Expression oldFoundArgs = foundArgs;
+        Expression oldFoundConstant = foundConstant;
+        inPropertyExpression = true;
+        foundArgs = null;
+        foundConstant = null;
+        Expression objectExpression = transform(pe.getObjectExpression());
+        boolean candidate = false;
+        if (objectExpression instanceof MethodCallExpression) {
+            candidate = 
((MethodCallExpression)objectExpression).isImplicitThis();
+        }
+
+        if (foundArgs != null && foundConstant != null && candidate) {
+            Expression result = 
findStaticMethodImportFromModule(foundConstant, foundArgs);
+            if (result != null) {
+                objectExpression = result;
+                objectExpression.setSourcePosition(pe);
+            }
+        }
+        inPropertyExpression = oldInPropertyExpression;
+        foundArgs = oldFoundArgs;
+        foundConstant = oldFoundConstant;
+        pe.setObjectExpression(objectExpression);
+        return pe;
+    }
+
+    private Expression findStaticFieldOrPropAccessorImportFromModule(String 
name) {
+        ModuleNode module = currentClass.getModule();
+        if (module == null) return null;
+        Map<String, ImportNode> importNodes = module.getStaticImports();
+        Expression expression;
+        String accessorName = getAccessorName(name);
+        // look for one of these:
+        //   import static MyClass.setProp [as setOtherProp]
+        //   import static MyClass.getProp [as getOtherProp]
+        // when resolving prop reference
+        if (importNodes.containsKey(accessorName)) {
+            expression = findStaticProperty(importNodes, accessorName);
+            if (expression != null) return expression;
+        }
+        if (accessorName.startsWith("get")) {
+            accessorName = "is" + accessorName.substring(3);
+            if (importNodes.containsKey(accessorName)) {
+                expression = findStaticProperty(importNodes, accessorName);
+                if (expression != null) return expression;
+            }
+        }
+
+        // look for one of these:
+        //   import static MyClass.prop [as otherProp]
+        // when resolving prop or field reference
+        if (importNodes.containsKey(name)) {
+            ImportNode importNode = importNodes.get(name);
+            expression = findStaticPropertyAccessor(importNode.getType(), 
importNode.getFieldName());
+            if (expression != null) return expression;
+            expression = findStaticField(importNode.getType(), 
importNode.getFieldName());
+            if (expression != null) return expression;
+        }
+        // look for one of these:
+        //   import static MyClass.*
+        // when resolving prop or field reference
+        for (ImportNode importNode : module.getStaticStarImports().values()) {
+            ClassNode node = importNode.getType();
+            expression = findStaticPropertyAccessor(node, name);
+            if (expression != null) return expression;
+            expression = findStaticField(node, name);
+            if (expression != null) return expression;
+        }
+        return null;
+    }
+
+    private Expression findStaticProperty(Map<String, ImportNode> importNodes, 
String accessorName) {
+        Expression result = null;
+        ImportNode importNode = importNodes.get(accessorName);
+        ClassNode importClass = importNode.getType();
+        String importMember = importNode.getFieldName();
+        result = findStaticPropertyAccessorByFullName(importClass, 
importMember);
+        if (result == null) {
+            result = findStaticPropertyAccessor(importClass, 
getPropNameForAccessor(importMember));
+        }
+        return result;
+    }
+
+    private Expression findStaticMethodImportFromModule(Expression method, 
Expression args) {
+        ModuleNode module = currentClass.getModule();
+        if (module == null || !(method instanceof ConstantExpression)) return 
null;
+        Map<String, ImportNode> importNodes = module.getStaticImports();
+        ConstantExpression ce = (ConstantExpression) method;
+        Expression expression;
+        Object value = ce.getValue();
+        // skip non-Strings, e.g. Integer
+        if (!(value instanceof String)) return null;
+        final String name = (String) value;
+        // look for one of these:
+        //   import static SomeClass.method [as otherName]
+        // when resolving methodCall() or getProp() or setProp()
+        if (importNodes.containsKey(name)) {
+            ImportNode importNode = importNodes.get(name);
+            expression = findStaticMethod(importNode.getType(), 
importNode.getFieldName(), args);
+            if (expression != null) return expression;
+            expression = 
findStaticPropertyAccessorGivenArgs(importNode.getType(), 
getPropNameForAccessor(importNode.getFieldName()), args);
+            if (expression != null) {
+                return new StaticMethodCallExpression(importNode.getType(), 
importNode.getFieldName(), args);
+            }
+        }
+        // look for one of these:
+        //   import static SomeClass.someProp [as otherName]
+        // when resolving getProp() or setProp()
+        if (isValidAccessorName(name)) {
+            String propName = getPropNameForAccessor(name);
+            if (importNodes.containsKey(propName)) {
+                ImportNode importNode = importNodes.get(propName);
+                ClassNode importClass = importNode.getType();
+                String importMember = importNode.getFieldName();
+                expression = findStaticMethod(importClass, prefix(name) + 
capitalize(importMember), args);
+                if (expression != null) return expression;
+                expression = findStaticPropertyAccessorGivenArgs(importClass, 
importMember, args);
+                if (expression != null) {
+                    return new StaticMethodCallExpression(importClass, 
prefix(name) + capitalize(importMember), args);
+                }
+            }
+        }
+        Map<String, ImportNode> starImports = module.getStaticStarImports();
+        ClassNode starImportType;
+        if (currentClass.isEnum() && 
starImports.containsKey(currentClass.getName())) {
+            ImportNode importNode = starImports.get(currentClass.getName());
+            starImportType = importNode == null ? null : importNode.getType();
+            expression = findStaticMethod(starImportType, name, args);
+            if (expression != null) return expression;
+        } else {
+            for (ImportNode importNode : starImports.values()) {
+                starImportType = importNode == null ? null : 
importNode.getType();
+                expression = findStaticMethod(starImportType, name, args);
+                if (expression != null) return expression;
+                expression = 
findStaticPropertyAccessorGivenArgs(starImportType, 
getPropNameForAccessor(name), args);
+                if (expression != null) {
+                    return new StaticMethodCallExpression(starImportType, 
name, args);
+                }
+            }
+        }
+        return null;
+    }
+
+    private static String prefix(String name) {
+        return name.startsWith("is") ? "is" : name.substring(0, 3);
+    }
+
+    private String getAccessorName(String name) {
+        return (inLeftExpression ? "set" : "get") + capitalize(name);
+    }
+
+    private Expression findStaticPropertyAccessorGivenArgs(ClassNode 
staticImportType, String propName, Expression args) {
+        // TODO validate args?
+        return findStaticPropertyAccessor(staticImportType, propName);
+    }
+
+    private Expression findStaticPropertyAccessor(ClassNode staticImportType, 
String propName) {
+        String accessorName = getAccessorName(propName);
+        Expression accessor = 
findStaticPropertyAccessorByFullName(staticImportType, accessorName);
+        if (accessor == null && accessorName.startsWith("get")) {
+            accessor = findStaticPropertyAccessorByFullName(staticImportType, 
"is" + accessorName.substring(3));
+        }
+        if (accessor == null && hasStaticProperty(staticImportType, propName)) 
{
+            // args will be replaced
+            if (inLeftExpression)
+                accessor = new StaticMethodCallExpression(staticImportType, 
accessorName, ArgumentListExpression.EMPTY_ARGUMENTS);
+            else
+                accessor = new PropertyExpression(new 
ClassExpression(staticImportType), propName);
+        }
+        return accessor;
+    }
+
+    private Expression findStaticPropertyAccessorByFullName(ClassNode 
staticImportType, String accessorMethodName) {
+        // anything will do as we only check size == 1
+        ArgumentListExpression dummyArgs = new ArgumentListExpression();
+        dummyArgs.addExpression(new EmptyExpression());
+        return findStaticMethod(staticImportType, accessorMethodName, 
(inLeftExpression ? dummyArgs : ArgumentListExpression.EMPTY_ARGUMENTS));
+    }
+
+    private static Expression findStaticField(ClassNode staticImportType, 
String fieldName) {
+        if (staticImportType.isPrimaryClassNode() || 
staticImportType.isResolved()) {
+            FieldNode field = getField(staticImportType, fieldName);
+            if (field != null && field.isStatic())
+                return new PropertyExpression(new 
ClassExpression(staticImportType), fieldName);
+        }
+        return null;
+    }
+
+    private static FieldNode getField(ClassNode classNode, String fieldName) {
+        ClassNode node = classNode;
+        Set<String> visited = new HashSet<String>();
+        while (node != null) {
+            FieldNode fn = node.getDeclaredField(fieldName);
+            if (fn != null) return fn;
+            ClassNode[] interfaces = node.getInterfaces();
+            for (ClassNode iNode : interfaces) {
+                if (visited.contains(iNode.getName())) continue;
+                FieldNode ifn = getField(iNode, fieldName);
+                visited.add(iNode.getName());
+                if (ifn != null) return ifn;
+            }
+            node = node.getSuperClass();
+        }
+        return null;
+    }
+
+    private static Expression findStaticMethod(ClassNode staticImportType, 
String methodName, Expression args) {
+        if (staticImportType.isPrimaryClassNode() || 
staticImportType.isResolved()) {
+            if (staticImportType.hasPossibleStaticMethod(methodName, args)) {
+                return new StaticMethodCallExpression(staticImportType, 
methodName, args);
+            }
+        }
+        return null;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/StaticVerifier.java 
b/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
new file mode 100644
index 0000000..53706f9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
@@ -0,0 +1,204 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+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
+ */
+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;
+
+    public void visitClass(ClassNode node, SourceUnit source) {
+        this.source = source;
+        super.visitClass(node);
+    }
+
+    @Override
+    public void visitVariableExpression(VariableExpression ve) {
+        Variable v = ve.getAccessedVariable();
+        if (v != null && v instanceof DynamicVariable) {
+            if (!inPropertyExpression || inSpecialConstructorCall) 
addStaticVariableError(ve);
+        }
+    }
+
+    @Override
+    public void visitClosureExpression(ClosureExpression ce) {
+        boolean oldInClosure = inClosure;
+        inClosure = true;
+        super.visitClosureExpression(ce);
+        inClosure = oldInClosure;
+    }
+
+    @Override
+    public void visitConstructorCallExpression(ConstructorCallExpression cce) {
+        boolean oldIsSpecialConstructorCall = inSpecialConstructorCall;
+        inSpecialConstructorCall = cce.isSpecialCall();
+        super.visitConstructorCallExpression(cce);
+        inSpecialConstructorCall = oldIsSpecialConstructorCall;
+    }
+
+    @Override
+    public void visitConstructorOrMethod(MethodNode node, boolean 
isConstructor) {
+        MethodNode oldCurrentMethod = currentMethod;
+        currentMethod = node;
+        super.visitConstructorOrMethod(node, isConstructor);
+        if (isConstructor) {
+            final Set<String> exceptions = new HashSet<String>();
+            for (final Parameter param : node.getParameters()) {
+                exceptions.add(param.getName());
+                if (param.hasInitialExpression()) {
+                    param.getInitialExpression().visit(new 
CodeVisitorSupport() {
+                        @Override
+                        public void visitVariableExpression(VariableExpression 
ve) {
+                            if (exceptions.contains(ve.getName())) return;
+                            Variable av = ve.getAccessedVariable();
+                            if (av instanceof DynamicVariable || 
!av.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;
+                }
+            }
+        }
+        super.visitMethodCallExpression(mce);
+    }
+
+    @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);
+            }
+            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;
+        }
+        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) {
+        ClassNode node = cn;
+        while (node != null) {
+            FieldNode fn = node.getDeclaredField(fieldName);
+            if (fn != null) return fn;
+            List<ClassNode> interfacesToCheck = new 
ArrayList<ClassNode>(Arrays.asList(node.getInterfaces()));
+            while (!interfacesToCheck.isEmpty()) {
+                ClassNode nextInterface = interfacesToCheck.remove(0);
+                fn = nextInterface.getDeclaredField(fieldName);
+                if (fn != null) return fn;
+                
interfacesToCheck.addAll(Arrays.asList(nextInterface.getInterfaces()));
+            }
+            node = node.getSuperClass();
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/XStreamUtils.java 
b/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
new file mode 100644
index 0000000..3f7ccd3
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.StaxDriver;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.net.URI;
+
+public abstract class XStreamUtils {
+
+    public static void serialize(final String name, final Object ast) {
+        if (name == null || name.length() == 0) return;
+
+        XStream xstream = new XStream(new StaxDriver());
+        FileWriter astFileWriter = null;
+        try {
+            File astFile = astFile(name);
+            if (astFile == null) {
+                System.out.println("File-name for writing " + name + " AST 
could not be determined!");
+                return;
+            }
+            astFileWriter = new FileWriter(astFile, false);
+            xstream.toXML(ast, astFileWriter);
+            System.out.println("Written AST to " + name + ".xml");
+
+        } catch (Exception e) {
+            System.out.println("Couldn't write to " + name + ".xml");
+            e.printStackTrace();
+        } finally {
+            DefaultGroovyMethods.closeQuietly(astFileWriter);
+        }
+    }
+
+    /**
+     * Takes the incoming file-name and checks whether this is a URI using the 
<tt>file:</tt> protocol or a non-URI and treats
+     * it accordingly.
+     *
+     * @return a file-name {@link java.io.File} representation or 
<tt>null</tt> if the file-name was in an invalid URI format
+     */
+    private static File astFile(final String uriOrFileName) {
+        try {
+            final String astFileName = uriOrFileName + ".xml";
+            return uriOrFileName.startsWith("file:") ? new 
File(URI.create(astFileName)) : new File(astFileName);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
 
b/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
new file mode 100644
index 0000000..8f9e81c
--- /dev/null
+++ 
b/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control.customizers;
+
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilePhase;
+
+/**
+ * Users wanting to customize the configuration process such as adding 
imports, restricting the
+ * language features or apply AST transformations by default should implement 
this class, then
+ * call the {@link 
org.codehaus.groovy.control.CompilerConfiguration#addCompilationCustomizers(CompilationCustomizer...)}
+ * method.
+ *
+ * @author Cedric Champeau
+ *
+ * @since 1.8.0
+ *
+ */
+public abstract class CompilationCustomizer extends 
CompilationUnit.PrimaryClassNodeOperation {
+    private final CompilePhase phase;
+
+    public CompilationCustomizer(CompilePhase phase) {
+        this.phase = phase;
+    }
+
+    public CompilePhase getPhase() {
+        return phase;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java
 
b/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java
new file mode 100644
index 0000000..0f6af6a
--- /dev/null
+++ 
b/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control.customizers;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.SourceUnit;
+
+/**
+ * Base class for compilation customizers which delegate to another 
customizer. The phase this
+ * customizer runs at is retrieved from the phase of the delegate.
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+public abstract class DelegatingCustomizer extends CompilationCustomizer {
+    protected final CompilationCustomizer delegate;
+
+    public DelegatingCustomizer(CompilationCustomizer delegate) {
+        super(delegate.getPhase());
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void call(final SourceUnit source, final GeneratorContext context, 
final ClassNode classNode) throws CompilationFailedException {
+        delegate.call(source, context, classNode);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java 
b/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java
new file mode 100644
index 0000000..780b554
--- /dev/null
+++ 
b/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java
@@ -0,0 +1,169 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control.customizers;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This compilation customizer allows addiing various types of imports to the 
compilation unit. Supports adding :
+ * <ul>
+ *     <li>standard imports thanks to {@link #addImport(String)}, {@link 
#addImport(String, String)} or {@link #addImports(String...)}</li>
+ *     <li>star imports thanks to {@link #addStarImport(String)} or {@link 
#addStarImports(String...)}</li>
+ *     <li>static imports thanks to {@link #addStaticImport(String, String)} 
or {@link #addStaticImport(String, String, String)}</li>
+ *     <li>static star imports thanks to {@link #addStaticStar(String)} or 
{@link #addStaticStars(String...)}</li>
+ * </ul>
+ *
+ * @author Cedric Champeau
+ *
+ * @since 1.8.0
+ *
+ */
+public class ImportCustomizer extends CompilationCustomizer {
+
+    private final List<Import> imports = new LinkedList<Import>();
+
+    public ImportCustomizer() {
+        super(CompilePhase.CONVERSION);
+    }
+
+    @Override
+    public void call(final SourceUnit source, final GeneratorContext context, 
final ClassNode classNode) throws CompilationFailedException {
+        final ModuleNode ast = source.getAST();
+        for (Import anImport : imports) {
+            switch (anImport.type) {
+                case regular:
+                    ast.addImport(anImport.alias, anImport.classNode);
+                    break;
+                case staticImport:
+                    ast.addStaticImport(anImport.classNode, anImport.field, 
anImport.alias);
+                    break;
+                case staticStar:
+                    ast.addStaticStarImport(anImport.alias, 
anImport.classNode);
+                    break;
+                case star:
+                    ast.addStarImport(anImport.star);
+                    break;
+            }
+        }
+    }
+
+    public ImportCustomizer addImport(final String alias, final String 
className) {
+        imports.add(new Import(ImportType.regular, alias, 
ClassHelper.make(className)));
+        return this;
+    }
+
+    public ImportCustomizer addStaticImport(final String className, final 
String fieldName) {
+        final ClassNode node = ClassHelper.make(className);
+        imports.add(new Import(ImportType.staticImport, fieldName, node, 
fieldName));
+        return this;
+    }
+
+    public ImportCustomizer addStaticStars(final String... classNames) {
+        for (String className : classNames) {
+            addStaticStar(className);
+        }
+        return this;
+    }
+
+    public ImportCustomizer addStaticImport(final String alias, final String 
className, final String fieldName) {
+        imports.add(new Import(ImportCustomizer.ImportType.staticImport, 
alias, ClassHelper.make(className), fieldName));
+        return this;
+    }
+
+    public ImportCustomizer addImports(final String... imports) {
+            for (String anImport : imports) {
+                addImport(anImport);
+            }
+        return this;
+    }
+
+    public ImportCustomizer addStarImports(final String... packageNames) {
+            for (String packageName : packageNames) {
+                addStarImport(packageName);
+            }
+        return this;
+    }
+
+    private void addImport(final String className) {
+        final ClassNode node = ClassHelper.make(className);
+        imports.add(new Import(ImportType.regular, 
node.getNameWithoutPackage(), node));
+    }
+
+    private void addStaticStar(final String className) {
+        imports.add(new Import(ImportCustomizer.ImportType.staticStar, 
className, ClassHelper.make(className)));
+    }
+
+    private void addStarImport(final String packagename) {
+        final String packageNameEndingWithDot = 
packagename.endsWith(".")?packagename:packagename+'.';
+        imports.add(new Import(ImportType.star,packageNameEndingWithDot));
+    }
+
+    // -------------------- Helper classes -------------------------
+
+    /**
+     * Represents imports which are possibly aliased.
+     */
+    private static final class Import {
+        final ImportType type;
+        final ClassNode classNode;
+        final String alias;
+        final String field;
+        final String star; // only used for star imports
+
+        private Import(final ImportType type, final String alias, final 
ClassNode classNode, final String field) {
+            this.alias = alias;
+            this.classNode = classNode;
+            this.field = field;
+            this.type = type;
+            this.star = null;
+        }
+
+        private Import(final ImportType type, final String alias, final 
ClassNode classNode) {
+            this.alias = alias;
+            this.classNode = classNode;
+            this.type = type;
+            this.field = null;
+            this.star = null;
+        }
+
+        private Import(final ImportType type, final String star) {
+            this.type = type;
+            this.star = star;
+            this.alias = null;
+            this.classNode = null;
+            this.field = null;
+        }
+    }
+
+    private enum ImportType {
+        regular,
+        staticImport,
+        staticStar,
+        star
+    }
+}

Reply via email to