213
213
import static org .codehaus .groovy .ast .tools .GeneralUtils .callX ;
214
214
import static org .codehaus .groovy .ast .tools .GeneralUtils .castX ;
215
215
import static org .codehaus .groovy .ast .tools .GeneralUtils .constX ;
216
+ import static org .codehaus .groovy .ast .tools .GeneralUtils .elvisX ;
216
217
import static org .codehaus .groovy .ast .tools .GeneralUtils .getGetterName ;
217
218
import static org .codehaus .groovy .ast .tools .GeneralUtils .getSetterName ;
218
219
import static org .codehaus .groovy .ast .tools .GeneralUtils .isOrImplements ;
@@ -1014,9 +1015,16 @@ private boolean ensureValidSetter(final Expression expression, final Expression
1014
1015
// because we need to check if a setter uses @DelegatesTo
1015
1016
VariableExpression receiver = varX ("%" , setterInfo .receiverType );
1016
1017
// for "x op= y" expression, find type as if it was "x = x op y"
1017
- Expression newRightExpression = isCompoundAssignment (expression )
1018
- ? binX (leftExpression , getOpWithoutEqual (expression ), rightExpression )
1019
- : rightExpression ;
1018
+ Expression valueExpression = rightExpression ;
1019
+ if (isCompoundAssignment (expression )) {
1020
+ Token op = ((BinaryExpression ) expression ).getOperation ();
1021
+ if (op .getType () == ELVIS_EQUAL ) { // GROOVY-10419: "x ?= y"
1022
+ valueExpression = elvisX (leftExpression , rightExpression );
1023
+ } else {
1024
+ op = Token .newSymbol (TokenUtil .removeAssignment (op .getType ()), op .getStartLine (), op .getStartColumn ());
1025
+ valueExpression = binX (leftExpression , op , rightExpression );
1026
+ }
1027
+ }
1020
1028
1021
1029
Function <Expression , MethodNode > setterCall = right -> {
1022
1030
MethodCallExpression call = callX (receiver , setterInfo .name , right );
@@ -1033,14 +1041,14 @@ private boolean ensureValidSetter(final Expression expression, final Expression
1033
1041
return type ;
1034
1042
};
1035
1043
1036
- MethodNode methodTarget = setterCall .apply (newRightExpression );
1044
+ MethodNode methodTarget = setterCall .apply (valueExpression );
1037
1045
if (methodTarget == null && !isCompoundAssignment (expression )) {
1038
1046
// if no direct match, try implicit conversion
1039
1047
for (MethodNode setter : setterInfo .setters ) {
1040
1048
ClassNode lType = setterType .apply (setter );
1041
- ClassNode rType = getDeclaredOrInferredType (newRightExpression );
1042
- if (checkCompatibleAssignmentTypes (lType , rType , newRightExpression , false )) {
1043
- methodTarget = setterCall .apply (castX (lType , newRightExpression ));
1049
+ ClassNode rType = getDeclaredOrInferredType (valueExpression );
1050
+ if (checkCompatibleAssignmentTypes (lType , rType , valueExpression , false )) {
1051
+ methodTarget = setterCall .apply (castX (lType , valueExpression ));
1044
1052
if (methodTarget != null ) {
1045
1053
break ;
1046
1054
}
@@ -1060,7 +1068,7 @@ private boolean ensureValidSetter(final Expression expression, final Expression
1060
1068
return false ;
1061
1069
} else {
1062
1070
ClassNode firstSetterType = setterType .apply (setterInfo .setters .get (0 ));
1063
- addAssignmentError (firstSetterType , getType (newRightExpression ), expression );
1071
+ addAssignmentError (firstSetterType , getType (valueExpression ), expression );
1064
1072
return true ;
1065
1073
}
1066
1074
}
@@ -1070,16 +1078,11 @@ private static boolean isClosureWithType(final ClassNode type) {
1070
1078
}
1071
1079
1072
1080
private static boolean isCompoundAssignment (final Expression exp ) {
1073
- if (!(exp instanceof BinaryExpression )) return false ;
1074
- int type = ((BinaryExpression ) exp ).getOperation ().getType ();
1075
- return isAssignment (type ) && type != ASSIGN ;
1076
- }
1077
-
1078
- private static Token getOpWithoutEqual (final Expression exp ) {
1079
- if (!(exp instanceof BinaryExpression )) return null ; // should never happen
1080
- Token op = ((BinaryExpression ) exp ).getOperation ();
1081
- int typeWithoutEqual = TokenUtil .removeAssignment (op .getType ());
1082
- return new Token (typeWithoutEqual , op .getText () /* will do */ , op .getStartLine (), op .getStartColumn ());
1081
+ if (exp instanceof BinaryExpression ) {
1082
+ Token op = ((BinaryExpression ) exp ).getOperation ();
1083
+ return isAssignment (op .getType ()) && op .getType () != EQUAL ;
1084
+ }
1085
+ return false ;
1083
1086
}
1084
1087
1085
1088
protected ClassNode getOriginalDeclarationType (final Expression lhs ) {
0 commit comments