You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/02/22 15:19:41 UTC
[groovy] branch GROOVY_2_5_X updated: GROOVY-9289: Delegate: check excludes/includes names against class names
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new 861ee93 GROOVY-9289: Delegate: check excludes/includes names against class names
861ee93 is described below
commit 861ee939e491520fcf10f9987862444e443279cb
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Feb 22 09:17:50 2022 -0600
GROOVY-9289: Delegate: check excludes/includes names against class names
2_5_X backport
---
.../transform/DelegateASTTransformation.java | 36 ++++++++++++++++++++++
.../groovy/transform/DelegateTransformTest.groovy | 20 ++++++++++++
2 files changed, 56 insertions(+)
diff --git a/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java
index ab40e67..461e76f 100644
--- a/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java
@@ -34,6 +34,7 @@ import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.tools.BeanUtils;
import org.codehaus.groovy.ast.tools.GenericsUtils;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
@@ -146,6 +147,9 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
delegate.includeTypes = getMemberClassList(node, MEMBER_INCLUDE_TYPES);
checkIncludeExcludeUndefinedAware(node, delegate.excludes, delegate.includes,
delegate.excludeTypes, delegate.includeTypes, MY_TYPE_NAME);
+ // GROOVY-9289: check excludes/includes names against the delegate's property and method names
+ if (!checkPropertyOrMethodList(delegate.type, delegate.excludes, "excludes", node, MY_TYPE_NAME)) return;
+ if (!checkPropertyOrMethodList(delegate.type, delegate.includes, "includes", node, MY_TYPE_NAME)) return;
final List<MethodNode> ownerMethods = getAllMethods(delegate.owner);
final List<MethodNode> delegateMethods = filterMethods(collectMethods(delegate.type), delegate, allNames, includeDeprecated);
@@ -270,6 +274,38 @@ next_signature: for (int i = 1; i <= n; i += 1) { // from Verifier#addDefaultPar
return methods;
}
+ private boolean checkPropertyOrMethodList(final ClassNode cNode, final List<String> propertyNameList, final String listName, final AnnotationNode anno, final String typeName) {
+ if (propertyNameList == null || propertyNameList.isEmpty()) {
+ return true;
+ }
+ final Set<String> pNames = new HashSet<>();
+ final Set<String> mNames = new HashSet<>();
+ for (PropertyNode pNode : BeanUtils.getAllProperties(cNode, false, false, false)) {
+ String name = pNode.getField().getName();
+ String suffix = capitalize(name);
+ pNames.add(name);
+ // add getter/setters since Groovy compiler hasn't added property accessors yet
+ if ((pNode.getModifiers() & ACC_FINAL) == 0) {
+ mNames.add("set" + suffix);
+ }
+ mNames.add("get" + suffix);
+ if (pNode.getOriginType().equals(ClassHelper.boolean_TYPE)) {
+ mNames.add("is" + suffix);
+ }
+ }
+ for (MethodNode mNode : cNode.getAllDeclaredMethods()) {
+ mNames.add(mNode.getName());
+ }
+ boolean result = true;
+ for (String name : propertyNameList) {
+ if (!pNames.contains(name) && !mNames.contains(name)) {
+ addError("Error during " + typeName + " processing: '" + listName + "' property or method '" + name + "' does not exist.", anno);
+ result = false;
+ }
+ }
+ return result;
+ }
+
private static void addSetterIfNeeded(final DelegateDescription delegate, final PropertyNode prop, final String name, final boolean allNames) {
String setterName = "set" + capitalize(name);
if ((prop.getModifiers() & ACC_FINAL) == 0
diff --git a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
index 3b7f3ab..82ffea5 100644
--- a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
@@ -859,6 +859,26 @@ final class DelegateTransformTest {
'''
}
+ @Test // GROOVY-9289
+ void testExcludesWithInvalidPropertyNameResultsInError() {
+ def err = shouldFail '''
+ class WMap {
+ String name
+ @Delegate(excludes = "name")
+ Map<String, String> data
+
+ WMap(String name, Map<String, String> data) {
+ this.name = name
+ this.data = data
+ }
+ }
+
+ new WMap('example', [name: 'weird'])
+ '''
+
+ assert err.message.contains("Error during @Delegate processing: 'excludes' property or method 'name' does not exist.")
+ }
+
@Test // GROOVY-8825
void testDelegateToPrecompiledGroovyGeneratedMethod() {
assertScript '''