Skip to content

Commit

Permalink
GROOVY-11399: STC: getDelegate(), getOwner(), getThisObject() type
Browse files Browse the repository at this point in the history
3_0_X backport
  • Loading branch information
eric-milles committed Jun 5, 2024
1 parent 63830fe commit 937cc54
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -585,30 +585,30 @@ public void visitVariableExpression(final VariableExpression vexp) {

if (enclosingClosure != null) {
switch (name) {
case "delegate":
DelegationMetadata dm = getDelegationMetadata(enclosingClosure.getClosureExpression());
if (dm != null) {
storeType(vexp, dm.getType());
return;
}
// falls through
case "owner":
if (typeCheckingContext.getEnclosingClosureStack().size() > 1) {
storeType(vexp, CLOSURE_TYPE);
return;
}
// falls through
case "thisObject":
storeType(vexp, typeCheckingContext.getEnclosingClassNode());
return;
case "parameterTypes":
storeType(vexp, CLASS_Type.makeArray());
case "delegate":
DelegationMetadata dm = getDelegationMetadata(enclosingClosure.getClosureExpression());
if (dm != null) {
vexp.putNodeMetaData(INFERRED_TYPE, dm.getType());
return;
case "maximumNumberOfParameters":
case "resolveStrategy":
case "directive":
storeType(vexp, int_TYPE);
}
// falls through
case "owner":
if (typeCheckingContext.getEnclosingClosureStack().size() > 1) {
vexp.putNodeMetaData(INFERRED_TYPE, CLOSURE_TYPE.getPlainNodeReference());
return;
}
// falls through
case "thisObject":
vexp.putNodeMetaData(INFERRED_TYPE, makeThis());
return;
case "parameterTypes":
vexp.putNodeMetaData(INFERRED_TYPE, CLASS_Type.getPlainNodeReference().makeArray());
return;
case "maximumNumberOfParameters":
case "resolveStrategy":
case "directive":
vexp.putNodeMetaData(INFERRED_TYPE, int_TYPE);
return;
}
}

Expand Down Expand Up @@ -3553,7 +3553,7 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
if (mn.isEmpty() && call.isImplicitThis() && isThisExpression(objectExpression) && typeCheckingContext.getEnclosingClosure() != null) {
mn = CLOSURE_TYPE.getDeclaredMethods(name);
if (!mn.isEmpty()) {
chosenReceiver = Receiver.make(CLOSURE_TYPE);
receiver = CLOSURE_TYPE.getPlainNodeReference();
objectExpression.removeNodeMetaData(INFERRED_TYPE);
}
}
Expand Down Expand Up @@ -3585,7 +3585,27 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
}

ClassNode returnType = getType(directMethodCallCandidate);
if (isUsingGenericsOrIsArrayUsingGenerics(returnType)) {
// GROOVY-5470, GROOVY-6091, GROOVY-9604, GROOVY-11399:
if (call.isImplicitThis() && isThisExpression(objectExpression) && typeCheckingContext.getEnclosingClosure() != null
&& (directMethodCallCandidate == GET_DELEGATE || directMethodCallCandidate == GET_OWNER || directMethodCallCandidate == GET_THISOBJECT)) {
switch (name) {
case "getDelegate":
DelegationMetadata dm = getDelegationMetadata(typeCheckingContext.getEnclosingClosure().getClosureExpression());
if (dm != null) {
returnType = dm.getType();
break;
}
// falls through
case "getOwner":
if (typeCheckingContext.getEnclosingClosureStack().size() > 1) {
returnType = CLOSURE_TYPE.getPlainNodeReference();
break;
}
// falls through
case "getThisObject":
returnType = makeThis();
}
} else if (isUsingGenericsOrIsArrayUsingGenerics(returnType)) {
visitMethodCallArguments(chosenReceiver.getType(), argumentList, true, directMethodCallCandidate);
for (Expression argument : argumentList.getExpressions()) {
if (argument instanceof ClosureExpression) {
Expand All @@ -3599,15 +3619,6 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
ClassNode irtg = inferReturnTypeGenerics(chosenReceiver.getType(), directMethodCallCandidate, callArguments, call.getGenericsTypes());
returnType = (irtg != null && implementsInterfaceOrIsSubclassOf(irtg, returnType) ? irtg : returnType);
}
// GROOVY-6091: use of "delegate" or "getDelegate()" does not make use of @DelegatesTo metadata
if (directMethodCallCandidate == GET_DELEGATE && typeCheckingContext.getEnclosingClosure() != null) {
DelegationMetadata md = getDelegationMetadata(typeCheckingContext.getEnclosingClosure().getClosureExpression());
if (md != null) {
returnType = md.getType();
} else {
returnType = typeCheckingContext.getEnclosingClassNode();
}
}
Parameter[] parameters = directMethodCallCandidate.getParameters();
// GROOVY-7106, GROOVY-7274, GROOVY-8909, GROOVY-8961, GROOVY-9734, GROOVY-9844, GROOVY-9915, et al.
if (chosenReceiver.getType().getGenericsTypes() != null && !directMethodCallCandidate.isStatic() && !(directMethodCallCandidate instanceof ExtensionMethodNode)) {
Expand Down Expand Up @@ -5164,9 +5175,6 @@ protected ClassNode getType(final ASTNode exp) {
return ((ConstructorCallExpression) exp).getType();
}
if (exp instanceof MethodNode) {
if ((exp == GET_DELEGATE || exp == GET_OWNER || exp == GET_THISOBJECT) && typeCheckingContext.getEnclosingClosure() != null) {
return typeCheckingContext.getEnclosingClassNode();
}
ClassNode ret = getInferredReturnType(exp);
return ret != null ? ret : ((MethodNode) exp).getReturnType();
}
Expand Down
94 changes: 0 additions & 94 deletions src/test/groovy/transform/stc/BugsSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -219,90 +219,6 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
'''
}

void testClosureThisObjectDelegateOwnerProperty() {
assertScript '''
class C {
void m() {
C that = this;
{ ->
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
})
def ref = thisObject
assert ref == that
}();
{ ->
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
})
def ref = delegate
assert ref == that
}();
{ ->
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
})
def ref = owner
assert ref == that
}();
}
}
new C().m()
'''
}

void testClosureThisObjectDelegateOwnerAccessor() {
assertScript '''
class C {
void m() {
C that = this;
{ ->
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
})
def ref = getThisObject()
assert ref == that
}();
{ ->
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
})
def ref = getDelegate()
assert ref == that
}();
{ ->
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
})
def ref = getOwner()
assert ref == that
}();
}
}
new C().m()
'''
}

// GROOVY-9604
void testClosureResolveStrategy() {
assertScript '''
class C {
def m() {
return { ->
resolveStrategy + getResolveStrategy()
}();
}
}
assert new C().m() == 0
'''
}

// GROOVY-5616
void testAssignToGroovyObject() {
assertScript '''
Expand Down Expand Up @@ -382,16 +298,6 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
execute()'''
}

// GROOVY-5874 (pt.1)
void testClosureSharedVariableInBinExp() {
shouldFailWithMessages '''
def sum = 0
def cl1 = { sum = sum + 1 }
def cl2 = { sum = new Date() }
''', 'A closure shared variable [sum] has been assigned with various types'
}

// GROOVY-5870
void testShouldNotThrowErrorIfTryingToCastToInterface() {
assertScript '''
Expand Down
Loading

0 comments on commit 937cc54

Please sign in to comment.