Skip to content

Commit

Permalink
GROOVY-11372: STC: write property via extension method
Browse files Browse the repository at this point in the history
4_0_X backport
  • Loading branch information
eric-milles committed May 10, 2024
1 parent 0456e0e commit 753c34a
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,25 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
return true;
}

// in case of a lookup on java.lang.Class, look for instance methods on Class
// as well; in case of static property access Class<Type> and Type are listed
boolean staticOnly = isClassClassNodeWrappingConcreteType(receiverType) ? false
: (receiver.getData() == null ? staticOnlyAccess : false);

List<MethodNode> setters = findSetters(wrapTypeIfNecessary(receiverType), setterName, /*voidOnly:*/false);
setters = allowStaticAccessToMember(setters, staticOnly);
// GROOVY-11319:
setters.removeIf(setter -> !hasAccessToMember(typeCheckingContext.getEnclosingClassNode(), setter.getDeclaringClass(), setter.getModifiers()));
// GROOVY-11372:
ClassLoader loader = getSourceUnit().getClassLoader();
Set<MethodNode> dgmSet = findDGMMethodsForClassNode(loader, receiverType, setterName);
if (isPrimitiveType(receiverType)) findDGMMethodsForClassNode(loader, getWrapper(receiverType), setterName, (java.util.TreeSet<MethodNode>) dgmSet);
for (MethodNode method : dgmSet) {
if ((!staticOnly || method.isStatic()) && method.getParameters().length == 1) {
setters.add(method);
}
}

LinkedList<ClassNode> queue = new LinkedList<>();
queue.add(receiverType);
if (isPrimitiveType(receiverType)) {
Expand All @@ -1546,11 +1565,6 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
Collections.addAll(queue, current.getInterfaces());
}

boolean staticOnly = (receiver.getData() == null ? staticOnlyAccess : false);
// in case of a lookup on java.lang.Class, look for instance methods on Class
// as well; in case of static property access Class<Type> and Type are listed
if (isClassClassNodeWrappingConcreteType(current)) staticOnly = false;

field = allowStaticAccessToMember(field, staticOnly);

// skip property/accessor checks for "x.@field"
Expand Down Expand Up @@ -1579,10 +1593,6 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
|| (!isThisExpression(objectExpression) && !isSuperExpression(objectExpression) && isOrImplements(objectExpressionType, MAP_TYPE)))) {
getter = null;
}
List<MethodNode> setters = findSetters(current, setterName, /*enforce void:*/false);
setters = allowStaticAccessToMember(setters, staticOnly);
// GROOVY-11319:
setters.removeIf(setter -> !hasAccessToMember(typeCheckingContext.getEnclosingClassNode(), setter.getDeclaringClass(), setter.getModifiers()));

if (readMode && getter != null && visitor != null) visitor.visitMethod(getter);

Expand Down Expand Up @@ -1635,7 +1645,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
foundGetterOrSetter = (foundGetterOrSetter || getter != null || !setters.isEmpty());
}

if (!readMode || isThisExpression(objectExpression) || isSuperExpression(objectExpression) || !isOrImplements(objectExpressionType, MAP_TYPE)) { // GROOVY-11370
if (readMode && (isThisExpression(objectExpression) || isSuperExpression(objectExpression) || !isOrImplements(objectExpressionType, MAP_TYPE))) { // GROOVY-11370, GROOVY-11372
// GROOVY-5568, GROOVY-9115, GROOVY-9123: the property may be defined by an extension
for (ClassNode dgmReceiver : isPrimitiveType(receiverType) ? new ClassNode[]{receiverType, getWrapper(receiverType)} : new ClassNode[]{receiverType}) {
Set<MethodNode> methods = findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), dgmReceiver, getterName);
Expand All @@ -1660,7 +1670,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
}
ClassNode returnType = inferReturnTypeGenerics(dgmReceiver, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
storeInferredTypeForPropertyExpression(pexp, returnType);
if (readMode) storeTargetMethod(pexp, getter);
storeTargetMethod(pexp, getter);
return true;
}
}
Expand Down
16 changes: 13 additions & 3 deletions src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
}

// GROOVY-5232
void testSetterForProperty() {
void testSetterForProperty1() {
assertScript '''
class Person {
String name
Expand All @@ -475,6 +475,16 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
'''
}

// GROOVY-11372
void testSetterForProperty2() {
assertScript '''
def baos = new ByteArrayOutputStream()
assert baos.size() == 0
baos.bytes= new byte[1]
assert baos.size() == 1
'''
}

// GROOVY-5443
void testFieldInitShouldPass() {
assertScript '''
Expand Down Expand Up @@ -690,13 +700,13 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
map.entry = null
map.empty = null // not read-only property
map.class = null // not read-only property
map.metaClass = null // TODO: 6549 SC is "put"
map.metaClass = null
map.properties = null
assert map.containsKey('entry')
assert map.containsKey('empty')
assert map.containsKey('class')
//assert !map.containsKey('metaClass')
assert !map.containsKey('metaClass')
assert map.containsKey('properties')
'''
}
Expand Down

0 comments on commit 753c34a

Please sign in to comment.