You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2017/04/24 14:13:10 UTC
[1/3] groovy git commit: GROOVY-8127: Access to
Trait$Trait$Helper#$self is forbidden (closes #529)
Repository: groovy
Updated Branches:
refs/heads/GROOVY_2_5_X 5f0a51f8a -> 2c8b68508
GROOVY-8127: Access to Trait$Trait$Helper#$self is forbidden (closes #529)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/c3b31c81
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/c3b31c81
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/c3b31c81
Branch: refs/heads/GROOVY_2_5_X
Commit: c3b31c8132e00c6a482764002e84a1b60491daea
Parents: f7c9867
Author: paulk <pa...@asert.com.au>
Authored: Mon Apr 24 18:02:34 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Tue Apr 25 00:12:56 2017 +1000
----------------------------------------------------------------------
.../transform/trait/TraitASTTransformation.java | 22 ++++----
.../groovy/transform/trait/TraitComposer.java | 7 +--
src/test/groovy/bugs/Groovy8127Bug.groovy | 53 ++++++++++++++++++++
3 files changed, 70 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/c3b31c81/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index 8222056..4ac7753 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -73,9 +73,13 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
import static org.codehaus.groovy.transform.trait.SuperCallTraitTransformer.UNRESOLVED_HELPER_CLASS;
/**
- * Handles generation of code for the @Trait annotation. A class annotated with @Trait will generate, instead: <ul>
- * <li>an <i>interface</i> with the same name</li> <li>an utility inner class that will be used by the compiler to
- * handle the trait</li> </ul>
+ * Handles generation of code for the traits (trait keyword is equivalent to using the @Trait annotation).
+ * A class annotated with @Trait will generate, instead:
+ * <ul>
+ * <li>an <i>interface</i> with the same name</li>
+ * <li>a utility inner class that will be used by the compiler to implement the trait</li>
+ * <li>potentially a utility inner class to assist with implementing trait fields</li>
+ * </ul>
*
* @author Cedric Champeau
*/
@@ -415,21 +419,21 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
Expression initialExpression = field.getInitialExpression();
MethodNode selectedMethod = field.isStatic()?staticInitializer:initializer;
if (initialExpression != null) {
+ VariableExpression thisObject = new VariableExpression(selectedMethod.getParameters()[0]);
+ ExpressionStatement initCode = new ExpressionStatement(initialExpression);
+ processBody(thisObject, initCode, trait, helper, fieldHelper, knownFields);
if (field.isFinal()) {
String baseName = field.isStatic() ? Traits.STATIC_INIT_METHOD : Traits.INIT_METHOD;
MethodNode fieldInitializer = new MethodNode(
baseName + Traits.remappedFieldName(trait, field.getName()),
ACC_STATIC | ACC_PUBLIC | ACC_SYNTHETIC,
field.getOriginType(),
- Parameter.EMPTY_ARRAY,
+ new Parameter[]{createSelfParameter(trait, field.isStatic())},
ClassNode.EMPTY_ARRAY,
- returnS(initialExpression)
+ returnS(initCode.getExpression())
);
helper.addMethod(fieldInitializer);
}
- VariableExpression thisObject = new VariableExpression(selectedMethod.getParameters()[0]);
- ExpressionStatement initCode = new ExpressionStatement(initialExpression);
- processBody(thisObject, initCode, trait, helper, fieldHelper, knownFields);
BlockStatement code = (BlockStatement) selectedMethod.getCode();
MethodCallExpression mce;
if (field.isStatic()) {
@@ -480,7 +484,7 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
ACC_STATIC | ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC,
field.getOriginType(),
fieldHelper,
- field.isFinal() ? initialExpression : null
+ null
);
// copy annotations from field to dummy field
List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
http://git-wip-us.apache.org/repos/asf/groovy/blob/c3b31c81/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java b/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
index 1025e61..b97f480 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
@@ -71,6 +71,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
@@ -257,13 +258,13 @@ public abstract class TraitComposer {
List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
List<AnnotationNode> notCopied = new LinkedList<AnnotationNode>();
GeneralUtils.copyAnnotatedNodeAnnotations(helperField, copied, notCopied);
- FieldNode fieldNode = cNode.addField(fieldName, fieldMods, returnType, (fieldMods & Opcodes.ACC_FINAL) == 0 ? null : helperField.getInitialExpression());
+ FieldNode fieldNode = cNode.addField(fieldName, fieldMods, returnType, null);
fieldNode.addAnnotations(copied);
// getInitialExpression above will be null if not in same source unit
// so instead set within (static) initializer
- if (fieldNode.isFinal() && !(helperClassNode instanceof InnerClassNode)) {
+ if (fieldNode.isFinal()) {
String baseName = fieldNode.isStatic() ? Traits.STATIC_INIT_METHOD : Traits.INIT_METHOD;
- Expression mce = callX(helperClassNode, baseName + fieldNode.getName());
+ Expression mce = callX(helperClassNode, baseName + fieldNode.getName(), args(varX("this")));
Statement stmt = stmt(assignX(varX(fieldNode.getName(), fieldNode.getType()), mce));
if (isStatic == 0) {
cNode.addObjectInitializerStatements(stmt);
http://git-wip-us.apache.org/repos/asf/groovy/blob/c3b31c81/src/test/groovy/bugs/Groovy8127Bug.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/bugs/Groovy8127Bug.groovy b/src/test/groovy/bugs/Groovy8127Bug.groovy
new file mode 100644
index 0000000..842390e
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy8127Bug.groovy
@@ -0,0 +1,53 @@
+/*
+ * 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 groovy.bugs
+
+import gls.CompilableTestSupport
+
+class Groovy8127Bug extends CompilableTestSupport {
+ void testTraitWithClosureReferencingField() {
+ assertScript """
+ trait BarTrait {
+ String result = ''
+ public final Runnable bar = { result = 'changeme' } as Runnable
+ void doRun() { bar.run() }
+ }
+
+ class Bar implements BarTrait {}
+
+ def b = new Bar()
+ b.doRun()
+ assert b.result == 'changeme'
+ """
+ }
+
+ void testTraitWithCompileStaticAndCoercedClosure() {
+ shouldCompile """
+ @groovy.transform.CompileStatic
+ trait FooTrait {
+ public final Runnable foo = { println new Date() } as Runnable
+ void doRun() { foo.run() }
+ }
+
+ class Foo implements FooTrait { }
+
+ new Foo().doRun()
+ """
+ }
+}
[3/3] groovy git commit: GROOVY-7579: Improve docs for invokeMethod
(closes #528)
Posted by pa...@apache.org.
GROOVY-7579: Improve docs for invokeMethod (closes #528)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/2c8b6850
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/2c8b6850
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/2c8b6850
Branch: refs/heads/GROOVY_2_5_X
Commit: 2c8b68508e036fdb1c01925dfefcdafa76a2a598
Parents: c3b31c8
Author: John Wagenleitner <jw...@apache.org>
Authored: Sun Apr 23 16:06:13 2017 -0700
Committer: paulk <pa...@asert.com.au>
Committed: Tue Apr 25 00:12:57 2017 +1000
----------------------------------------------------------------------
src/spec/doc/core-metaprogramming.adoc | 43 +++++++++++++++++------------
1 file changed, 25 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c8b6850/src/spec/doc/core-metaprogramming.adoc
----------------------------------------------------------------------
diff --git a/src/spec/doc/core-metaprogramming.adoc b/src/spec/doc/core-metaprogramming.adoc
index 52344fd..4609d7f 100644
--- a/src/spec/doc/core-metaprogramming.adoc
+++ b/src/spec/doc/core-metaprogramming.adoc
@@ -21,19 +21,19 @@
= Metaprogramming
-The Groovy language supports two flavors of metaprogramming: runtime metaprogramming and compile-time metaprogramming.
-The first one allows altering the class model and the behavior of a program at runtime, while the second only occurs
-at compile-time. Both have pros and cons, that we will detail in this section.
+The Groovy language supports two flavors of metaprogramming: runtime and compile-time.
+The first allows altering the class model and the behavior of a program at runtime while the second only occurs
+at compile-time. Both have pros and cons that we will detail in this section.
== Runtime metaprogramming
-With runtime metaprogramming we can postpone to runtime the decision to intercept, inject and even synthesize methods of classes and interfaces. For a deep understanding of Groovy MOP we need to understand Groovy objects and Groovy's method handling.
-In Groovy we work with three kinds of objects: POJO, POGO and Groovy Interceptors. Groovy allows metaprogramming for all types of objects but in different manner.
+With runtime metaprogramming we can postpone to runtime the decision to intercept, inject and even synthesize methods of classes and interfaces. For a deep understanding of Groovy's metaobject protocol (MOP) we need to understand Groovy objects and Groovy's method handling.
+In Groovy we work with three kinds of objects: POJO, POGO and Groovy Interceptors. Groovy allows metaprogramming for all types of objects but in a different manner.
-- POJO - A regular Java object, whose class can be written in Java or any other language for the JVM.
-- POGO - A Groovy object, whose class is written in Groovy. It extends `java.lang.Object` and implements the gapi:groovy.lang.GroovyObject[] interface by default.
-- Groovy Interceptor - A Groovy object that implements the gapi:groovy.lang.GroovyInterceptable[] interface and has method-interception capability, which we'll discuss in the <<core-metaprogramming.adoc#_groovyinterceptable,GroovyInterceptable>> section.
+- POJO - A regular Java object whose class can be written in Java or any other language for the JVM.
+- POGO - A Groovy object whose class is written in Groovy. It extends `java.lang.Object` and implements the gapi:groovy.lang.GroovyObject[] interface by default.
+- Groovy Interceptor - A Groovy object that implements the gapi:groovy.lang.GroovyInterceptable[] interface and has method-interception capability which is discussed in the <<core-metaprogramming.adoc#_groovyinterceptable,GroovyInterceptable>> section.
-For every method call Groovy checks whether the object is a POJO or a POGO. For POJOs, Groovy fetches it's `MetaClass` from the gapi:groovy.lang.MetaClassRegistry[] and delegates method invocation to it. For POGOs, Groovy takes more steps, as illustrated in the following figure:
+For every method call Groovy checks whether the object is a POJO or a POGO. For POJOs, Groovy fetches its `MetaClass` from the gapi:groovy.lang.MetaClassRegistry[] and delegates method invocation to it. For POGOs, Groovy takes more steps, as illustrated in the following figure:
.Groovy interception mechanism
image::assets/img/GroovyInterceptions.png[align="center"]
@@ -62,14 +62,21 @@ public interface GroovyObject {
==== invokeMethod
-According to the schema in <<core-metaprogramming.adoc#_runtime_metaprogramming,Runtime Metaprogramming>> this method is called when the method you called is not present on a Groovy object.
-Here is a simple example using a overridden `invokeMethod()` method:
+This method is primarily intended to be used in conjunction with the <<core-metaprogramming.adoc#_groovyinterceptable,GroovyInterceptable>>
+interface or an object's `MetaClass` where it will intercept all method calls.
+
+It is also invoked when the method called is not present on a Groovy object. Here is a simple example using an
+overridden `invokeMethod()` method:
[source,groovy]
----
include::{projectdir}/src/spec/test/metaprogramming/GroovyObjectTest.groovy[tags=groovy_invoke_method,indent=0]
----
+However, the use of `invokeMethod` to intercept missing methods is discouraged. In cases where the intent is to only
+intercept method calls in the case of a failed method dispatch use <<core-metaprogramming.adoc#_methodmissing,methodMissing>>
+instead.
+
==== get/setProperty
Every read access to a property can be intercepted by overriding the `getProperty()` method of the current object.
@@ -90,7 +97,7 @@ include::{projectdir}/src/spec/test/metaprogramming/GroovyObjectTest.groovy[tags
==== get/setMetaClass
-You can a access an object's `metaClass` or set your own `MetaClass` implementation for changing the default interception mechanism. For example you can write your own implementation of the `MetaClass` interface and assign to it to objects and accordingly change the interception mechanism:
+You can a access an object's `metaClass` or set your own `MetaClass` implementation for changing the default interception mechanism. For example, you can write your own implementation of the `MetaClass` interface and assign it to objects in order to change the interception mechanism:
[source,groovy]
----
@@ -106,7 +113,7 @@ You can find an additional example in the <<core-metaprogramming.adoc#_groovyint
=== get/setAttribute
-This functionality is related to the `MetaClass` implementation. In the default implementation you can access fields without invoking their getters and setters. The examples below demonstrate this approach:
+This functionality is related to the `MetaClass` implementation. In the default implementation you can access fields without invoking their getters and setters. The examples below demonstrates this approach:
[source, groovy]
----
@@ -121,7 +128,7 @@ include::{projectdir}/src/spec/test/metaprogramming/GroovyObjectTest.groovy[tags
=== methodMissing
Groovy supports the concept of `methodMissing`. This method differs from `invokeMethod` in that it
-is only invoked in case of a failed method dispatch, when no method can be found for the given name and/or the
+is only invoked in the case of a failed method dispatch when no method can be found for the given name and/or the
given arguments:
[source,groovy]
@@ -131,7 +138,7 @@ include::{projectdir}/src/spec/test/metaprogramming/MethodPropertyMissingTest.gr
Typically when using `methodMissing` it is possible to cache the result for the next time the same method is called.
-For example consider dynamic finders in GORM. These are implemented in terms of `methodMissing`. The code resembles
+For example, consider dynamic finders in GORM. These are implemented in terms of `methodMissing`. The code resembles
something like this:
[source,groovy]
@@ -194,7 +201,7 @@ package groovy.lang;
public interface GroovyInterceptable extends GroovyObject {
}
----
-When a Groovy object implements the `GroovyInterceptable` interface, it's `invokeMethod()` is called for any method calls. Below you can see a simple example of a object of this type:
+When a Groovy object implements the `GroovyInterceptable` interface, its `invokeMethod()` is called for any method calls. Below you can see a simple example of a object of this type:
[source,groovy]
----
@@ -209,9 +216,9 @@ include::{projectdir}/src/spec/test/metaprogramming/InterceptableTest.groovy[tag
----
[NOTE]
-We cannot use default groovy methods like `println` because these methods are injected into all groovy objects so they will be intercepted too.
+We cannot use default groovy methods like `println` because these methods are injected into all Groovy objects so they will be intercepted too.
-If we want to intercept all methods call but do not want to implement the `GroovyInterceptable` interface we can implement `invokeMethod()` on an object's `MetaClass`.
+If we want to intercept all method calls but do not want to implement the `GroovyInterceptable` interface we can implement `invokeMethod()` on an object's `MetaClass`.
This approach works for both POGOs and POJOs, as shown by this example:
[source,groovy]
[2/3] groovy git commit: refactor(idea): do not add blank line after
Copyright
Posted by pa...@apache.org.
refactor(idea): do not add blank line after Copyright
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/f7c9867d
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/f7c9867d
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/f7c9867d
Branch: refs/heads/GROOVY_2_5_X
Commit: f7c9867d7ebe72417eb4e5d8aef7b03322561a01
Parents: 5f0a51f
Author: John Wagenleitner <jw...@apache.org>
Authored: Sat Apr 22 08:22:30 2017 -0700
Committer: paulk <pa...@asert.com.au>
Committed: Tue Apr 25 00:12:56 2017 +1000
----------------------------------------------------------------------
gradle/idea.gradle | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/f7c9867d/gradle/idea.gradle
----------------------------------------------------------------------
diff --git a/gradle/idea.gradle b/gradle/idea.gradle
index 510a9cc..21af30f 100644
--- a/gradle/idea.gradle
+++ b/gradle/idea.gradle
@@ -68,7 +68,12 @@ idea {
<option name="myName" value="ASL2" />
<option name="myLocal" value="true" />
</copyright>
- ''')
+ ''')
+ appendNode(copyrightManager, '''
+ <LanguageOptions name="__TEMPLATE__">
+ <option name="addBlankAfter" value="false" />
+ </LanguageOptions>
+ ''')
}
def compilerConfig = node.component.find { it.@name == 'CompilerConfiguration' }