Repository: groovy
Updated Branches:
  refs/heads/master 7d9a54bb1 -> a2565bebb


GROOVY-7750: @Lazy allows instantiation of abstract class


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/a2565beb
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/a2565beb
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/a2565beb

Branch: refs/heads/master
Commit: a2565bebba790545a062525cb1f471dc62117225
Parents: 7d9a54b
Author: paulk <pa...@asert.com.au>
Authored: Tue May 17 21:06:50 2016 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Tue May 24 22:05:24 2016 +1000

----------------------------------------------------------------------
 .../groovy/ast/ClassCodeVisitorSupport.java     |  5 +--
 src/main/org/codehaus/groovy/ast/ClassNode.java |  4 +++
 .../groovy/ast/tools/GenericsUtils.java         |  2 +-
 .../groovy/classgen/ExtendedVerifier.java       |  2 +-
 .../tools/javac/JavaAwareResolveVisitor.java    |  2 +-
 .../transform/AbstractASTTransformation.java    | 32 ++++++++++----------
 .../groovy/transform/ErrorCollecting.java       | 31 +++++++++++++++++++
 .../transform/FieldASTTransformation.java       |  2 +-
 .../groovy/transform/LazyASTTransformation.java | 19 +++++++-----
 .../stc/StaticTypeCheckingVisitor.java          |  2 +-
 .../groovy/transform/LazyTransformTest.groovy   | 14 +++++++++
 .../MarkupTemplateTypeCheckingExtension.groovy  |  2 +-
 12 files changed, 85 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java 
b/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
index 7cd5807..bfabea9 100644
--- a/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
+++ b/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
@@ -43,8 +43,9 @@ import org.codehaus.groovy.ast.stmt.WhileStatement;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
 import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.transform.ErrorCollecting;
 
-public abstract class ClassCodeVisitorSupport extends CodeVisitorSupport 
implements GroovyClassVisitor {
+public abstract class ClassCodeVisitorSupport extends CodeVisitorSupport 
implements ErrorCollecting, GroovyClassVisitor {
 
     public void visitClass(ClassNode node) {
         visitAnnotations(node);
@@ -149,7 +150,7 @@ public abstract class ClassCodeVisitorSupport extends 
CodeVisitorSupport impleme
         if (init != null) init.visit(this);
     }
 
-    protected void addError(String msg, ASTNode expr) {
+    public void addError(String msg, ASTNode expr) {
         SourceUnit source = getSourceUnit();
         source.getErrorCollector().addErrorAndContinue(
                 new SyntaxErrorMessage(new SyntaxException(msg + '\n', 
expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), 
expr.getLastColumnNumber()), source)

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/ast/ClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/ClassNode.java 
b/src/main/org/codehaus/groovy/ast/ClassNode.java
index 2cde68c..6601ac7 100644
--- a/src/main/org/codehaus/groovy/ast/ClassNode.java
+++ b/src/main/org/codehaus/groovy/ast/ClassNode.java
@@ -1345,6 +1345,10 @@ public class ClassNode extends AnnotatedNode implements 
Opcodes {
         return (getModifiers() & Opcodes.ACC_INTERFACE) > 0;
     }
 
+    public boolean isAbstract(){
+        return (getModifiers() & Opcodes.ACC_ABSTRACT) > 0;
+    }
+
     public boolean isResolved() {
         if (clazz != null) return true;
         if (redirect != null) return redirect.isResolved();

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java 
b/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 53b7c1d..79449e4 100644
--- a/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -554,7 +554,7 @@ public class GenericsUtils {
         dummyClass.addMethod(dummyMN);
         ResolveVisitor visitor = new ResolveVisitor(compilationUnit) {
             @Override
-            protected void addError(final String msg, final ASTNode expr) {
+            public void addError(final String msg, final ASTNode expr) {
                 sourceUnit.addError(new IncorrectTypeHintException(mn, msg, 
usage.getLineNumber(), usage.getColumnNumber()));
             }
         };

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java 
b/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
index 14697e6..57cfbfa 100644
--- a/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
+++ b/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
@@ -278,7 +278,7 @@ public class ExtendedVerifier extends 
ClassCodeVisitorSupport {
         return 
CompilerConfiguration.isPostJDK5(this.source.getConfiguration().getTargetBytecode());
     }
 
-    protected void addError(String msg, ASTNode expr) {
+    public void addError(String msg, ASTNode expr) {
         this.source.getErrorCollector().addErrorAndContinue(
                 new SyntaxErrorMessage(
                         new SyntaxException(msg + '\n', expr.getLineNumber(), 
expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), 
this.source)

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/tools/javac/JavaAwareResolveVisitor.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/tools/javac/JavaAwareResolveVisitor.java 
b/src/main/org/codehaus/groovy/tools/javac/JavaAwareResolveVisitor.java
index aca9544..4291ac4 100644
--- a/src/main/org/codehaus/groovy/tools/javac/JavaAwareResolveVisitor.java
+++ b/src/main/org/codehaus/groovy/tools/javac/JavaAwareResolveVisitor.java
@@ -63,7 +63,7 @@ public class JavaAwareResolveVisitor extends ResolveVisitor {
         // do nothing here, leave it to the normal resolving
     }
 
-    protected void addError(String msg, ASTNode expr) {
+    public void addError(String msg, ASTNode expr) {
         // do nothing here, leave it to the normal resolving
     }
 }

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java 
b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
index b762153..17eef57 100644
--- a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
@@ -50,7 +50,7 @@ import static groovy.transform.Undefined.isUndefined;
 import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getInstanceNonPropertyFieldNames;
 import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getInstancePropertyNames;
 
-public abstract class AbstractASTTransformation implements Opcodes, 
ASTTransformation {
+public abstract class AbstractASTTransformation implements Opcodes, 
ASTTransformation, ErrorCollecting {
     public static final ClassNode RETENTION_CLASSNODE = 
ClassHelper.makeWithoutCaching(Retention.class);
 
     protected SourceUnit sourceUnit;
@@ -248,7 +248,7 @@ public abstract class AbstractASTTransformation implements 
Opcodes, ASTTransform
 
     public boolean hasAnnotation(ClassNode cNode, ClassNode annotation) {
         List annots = cNode.getAnnotations(annotation);
-        return (annots != null && !annots.isEmpty());
+        return (annots != null && !annots.isEmpty());
     }
 
     public static List<String> tokenize(String rawExcludes) {
@@ -260,23 +260,23 @@ public abstract class AbstractASTTransformation 
implements Opcodes, ASTTransform
     }
 
     public static boolean shouldSkipUndefinedAware(String name, List<String> 
excludes, List<String> includes) {
-        return shouldSkipUndefinedAware(name, excludes, includes, false);
-    }
-
-    public static boolean shouldSkipUndefinedAware(String name, List<String> 
excludes, List<String> includes, boolean allNames) {
-        return (excludes != null && excludes.contains(name)) ||
-            (!allNames && deemedInternalName(name)) ||
-            (includes != null && !includes.contains(name));
+        return shouldSkipUndefinedAware(name, excludes, includes, false);
+    }
+
+    public static boolean shouldSkipUndefinedAware(String name, List<String> 
excludes, List<String> includes, boolean allNames) {
+        return (excludes != null && excludes.contains(name)) ||
+            (!allNames && deemedInternalName(name)) ||
+            (includes != null && !includes.contains(name));
     }
 
     public static boolean shouldSkip(String name, List<String> excludes, 
List<String> includes) {
-        return shouldSkip(name, excludes, includes, false);
-    }
-
-    public static boolean shouldSkip(String name, List<String> excludes, 
List<String> includes, boolean allNames) {
-        return (excludes != null && excludes.contains(name)) ||
-            (!allNames && deemedInternalName(name)) ||
-            (includes != null && !includes.isEmpty() && 
!includes.contains(name));
+        return shouldSkip(name, excludes, includes, false);
+    }
+
+    public static boolean shouldSkip(String name, List<String> excludes, 
List<String> includes, boolean allNames) {
+        return (excludes != null && excludes.contains(name)) ||
+            (!allNames && deemedInternalName(name)) ||
+            (includes != null && !includes.isEmpty() && 
!includes.contains(name));
     }
 
     @Deprecated

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/transform/ErrorCollecting.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/ErrorCollecting.java 
b/src/main/org/codehaus/groovy/transform/ErrorCollecting.java
new file mode 100644
index 0000000..18d6008
--- /dev/null
+++ b/src/main/org/codehaus/groovy/transform/ErrorCollecting.java
@@ -0,0 +1,31 @@
+/*
+ * 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.transform;
+
+import org.codehaus.groovy.ast.ASTNode;
+
+/**
+ * An AST transform with the ability to report errors.
+ *
+ * @see ASTTransformation
+ */
+public interface ErrorCollecting {
+    void addError(String msg, ASTNode expr);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java 
b/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
index d0fee21..52b4406 100644
--- a/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
@@ -118,7 +118,7 @@ public class FieldASTTransformation extends 
ClassCodeExpressionTransformer imple
             for (AnnotationNode annotation : annotations) {
                 // GROOVY-6337 HACK: in case newly created field is @Lazy
                 if (annotation.getClassNode().equals(LAZY_TYPE)) {
-                    LazyASTTransformation.visitField(annotation, fieldNode);
+                    LazyASTTransformation.visitField(this, annotation, 
fieldNode);
                 }
                 final ClassNode annotationClassNode = 
annotation.getClassNode();
                 if (notTransform(annotationClassNode) || 
acceptableTransform(annotation)) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/transform/LazyASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/LazyASTTransformation.java 
b/src/main/org/codehaus/groovy/transform/LazyASTTransformation.java
index 5e25a3c..0216c47 100644
--- a/src/main/org/codehaus/groovy/transform/LazyASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/LazyASTTransformation.java
@@ -23,10 +23,12 @@ import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
@@ -58,9 +60,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 
 /**
  * Handles generation of code for the @Lazy annotation
- *
- * @author Alex Tkachman
- * @author Paul King
  */
 @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
 public class LazyASTTransformation extends AbstractASTTransformation {
@@ -75,13 +74,13 @@ public class LazyASTTransformation extends 
AbstractASTTransformation {
 
         if (parent instanceof FieldNode) {
             final FieldNode fieldNode = (FieldNode) parent;
-            visitField(node, fieldNode);
+            visitField(this, node, fieldNode);
         }
     }
 
-    static void visitField(AnnotationNode node, FieldNode fieldNode) {
+    static void visitField(ErrorCollecting xform, AnnotationNode node, 
FieldNode fieldNode) {
         final Expression soft = node.getMember("soft");
-        final Expression init = getInitExpr(fieldNode);
+        final Expression init = getInitExpr(xform, fieldNode);
 
         fieldNode.rename("$" + fieldNode.getName());
         fieldNode.setModifiers(ACC_PRIVATE | (fieldNode.getModifiers() & 
(~(ACC_PUBLIC | ACC_PROTECTED))));
@@ -207,11 +206,15 @@ public class LazyASTTransformation extends 
AbstractASTTransformation {
         return fieldNode.isStatic() ? classX(fieldNode.getDeclaringClass()) : 
varX("this");
     }
 
-    private static Expression getInitExpr(FieldNode fieldNode) {
+    private static Expression getInitExpr(ErrorCollecting xform, FieldNode 
fieldNode) {
         Expression initExpr = fieldNode.getInitialValueExpression();
         fieldNode.setInitialValueExpression(null);
 
-        if (initExpr == null) {
+        if (initExpr == null || initExpr instanceof EmptyExpression) {
+            if (fieldNode.getType().isAbstract()) {
+                xform.addError("You cannot lazily initialize '" + 
fieldNode.getName() + "' from the abstract class '" +
+                        fieldNode.getType().getName() + "'", fieldNode);
+            }
             initExpr = ctorX(fieldNode.getType());
         }
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java 
b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 6d3afb7..76d4249 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4603,7 +4603,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     }
 
     @Override
-    protected void addError(final String msg, final ASTNode expr) {
+    public void addError(final String msg, final ASTNode expr) {
         Long err = ((long) expr.getLineNumber()) << 16 + 
expr.getColumnNumber();
         if ((DEBUG_GENERATED_CODE && expr.getLineNumber()<0) || 
!typeCheckingContext.reportedErrors.contains(err)) {
             typeCheckingContext.getErrorCollector().addErrorAndContinue(new 
SyntaxErrorMessage(

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/src/test/org/codehaus/groovy/transform/LazyTransformTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/transform/LazyTransformTest.groovy 
b/src/test/org/codehaus/groovy/transform/LazyTransformTest.groovy
index 7ef7c1d..08a0b19 100644
--- a/src/test/org/codehaus/groovy/transform/LazyTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/LazyTransformTest.groovy
@@ -149,6 +149,20 @@ class LazyTransformTest extends GroovyShellTestCase {
         assert 
Modifier.isVolatile(res.class.getDeclaredField('$val2').modifiers)
     }
 
+    void testAbstractClassShouldNotCompile() {
+        def message = shouldFail {
+            new GroovyShell().run('''
+                abstract class Foo {}
+                class Demo {
+                    @Lazy Foo foo
+                }
+
+                new Demo().foo
+            ''', 'dummyFileName', [])
+        }
+        assert message.contains("You cannot lazily initialize 'foo' from the 
abstract class 'Foo'")
+    }
+
     void testSoft() {
         def res = evaluate("""
               class X {

http://git-wip-us.apache.org/repos/asf/groovy/blob/a2565beb/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateTypeCheckingExtension.groovy
----------------------------------------------------------------------
diff --git 
a/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateTypeCheckingExtension.groovy
 
b/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateTypeCheckingExtension.groovy
index 57cf170..db66f29 100644
--- 
a/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateTypeCheckingExtension.groovy
+++ 
b/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateTypeCheckingExtension.groovy
@@ -194,7 +194,7 @@ class MarkupTemplateTypeCheckingExtension extends 
GroovyTypeCheckingExtensionSup
         dummyClass.addMethod(dummyMN);
         ResolveVisitor visitor = new ResolveVisitor(ctx.compilationUnit) {
             @Override
-            protected void addError(final String msg, final ASTNode expr) {
+            public void addError(final String msg, final ASTNode expr) {
                 ctx.errorCollector.addErrorAndContinue(new SyntaxErrorMessage(
                         new SyntaxException(msg + '\n', expr.getLineNumber(), 
expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()),
                         ctx.source)

Reply via email to