@@ -54,6 +54,8 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {
54
54
case SimpleMemberAccessExpression =>
55
55
val base = createDotNetNodeInfo(expr.json(ParserKeys .Expression ))
56
56
Some (nodeTypeFullName(base))
57
+ case IdentifierName =>
58
+ scope.surroundingTypeDeclFullName
57
59
case _ =>
58
60
None
59
61
}
@@ -78,89 +80,167 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {
78
80
case _ => None
79
81
}
80
82
81
- private def astForSetterAssignmentExpression (
82
- assignExpr : DotNetNodeInfo ,
83
+ /** Mainly to abstract the lowering of +=, *=, etc. assignments when the LHS is a property. Takes care of building the
84
+ * RHS appropriately, e.g. by expanding `P += RHS` into `set_P(get_P() + RHS)`, etc.
85
+ * @param expr
86
+ * the full assignment expression, for `code`, `line`, etc.
87
+ * @param assignOp
88
+ * the assignment operator, cf. [[Operators ]]
89
+ * @param setterInfo
90
+ * the setter meta-data, cf. [[tryResolveSetterInvocation ]]
91
+ */
92
+ private def lowerSetterAssignmentRhs (
93
+ expr : DotNetNodeInfo ,
94
+ assignOp : String ,
83
95
setterInfo : (CSharpMethod , String ),
84
- lhs : DotNetNodeInfo ,
85
- opName : String ,
86
- rhsNode : DotNetNodeInfo
96
+ receiver : Option [Ast ],
97
+ rhs : DotNetNodeInfo
87
98
): Seq [Ast ] = {
88
99
val (setterMethod, setterBaseType) = setterInfo
100
+ val propertyName = setterMethod.name.stripPrefix(" set_" )
101
+ val originalRhs = astForOperand(rhs)
89
102
90
- lhs.node match {
91
- case SimpleMemberAccessExpression =>
92
- val baseNode = astForNode(createDotNetNodeInfo(lhs.json(ParserKeys .Expression )))
93
- val receiver = if setterMethod.isStatic then None else baseNode.headOption
94
- val propertyName = setterMethod.name.stripPrefix(" set_" )
95
- val originalRhs = astForOperand(rhsNode)
96
-
97
- val rhsAst = opName match {
98
- case Operators .assignment => originalRhs
99
- case _ =>
100
- scope.tryResolveGetterInvocation(propertyName, Some (setterBaseType)) match {
101
- // Shouldn't happen, provided it is valid code. At any rate, log and emit the RHS verbatim.
103
+ assignOp match {
104
+ case Operators .assignment => originalRhs
105
+ case _ =>
106
+ scope.tryResolveGetterInvocation(propertyName, Some (setterBaseType)) match {
107
+ // Shouldn't happen, provided it is valid code. At any rate, log and emit the RHS verbatim.
108
+ case None =>
109
+ logger.warn(s " Couldn't find matching getter for $propertyName in ${code(expr)}" )
110
+ originalRhs
111
+ case Some (getterMethod) =>
112
+ stripAssignmentFromOperator(assignOp) match {
102
113
case None =>
103
- logger.warn(s " Couldn't find matching getter for $propertyName in ${code(assignExpr )}" )
114
+ logger.warn(s " Unrecognized assignment in ${code(expr )}" )
104
115
originalRhs
105
- case Some (getterMethod) =>
106
- stripAssignmentFromOperator(opName) match {
107
- case None =>
108
- logger.warn(s " Unrecognized assignment in ${code(assignExpr)}" )
109
- originalRhs
110
- case Some (opName) =>
111
- val getterInvocation = createInvocationAst(
112
- assignExpr,
113
- getterMethod.name,
114
- Nil ,
115
- receiver,
116
- Some (getterMethod),
117
- Some (setterBaseType)
118
- )
119
- val operatorCall = newOperatorCallNode(
120
- opName,
121
- code(assignExpr),
122
- Some (setterMethod.returnType),
123
- line(assignExpr),
124
- column(assignExpr)
125
- )
126
- callAst(operatorCall, getterInvocation +: originalRhs, None , None ) :: Nil
127
- }
116
+ case Some (opName) =>
117
+ val getterInvocation =
118
+ createInvocationAst(expr, getterMethod.name, Nil , receiver, Some (getterMethod), Some (setterBaseType))
119
+ val operatorCall =
120
+ newOperatorCallNode(opName, code(expr), Some (setterMethod.returnType), line(expr), column(expr))
121
+ callAst(operatorCall, getterInvocation +: originalRhs, None , None ) :: Nil
128
122
}
129
123
}
124
+ }
125
+ }
126
+
127
+ /** Lowers assignments such as `x.P = RHS` and `x.P += RHS` with `P` denoting a setter property into calls
128
+ * `x.set_P(RHS)` and `x.set_P(x.get_P() + RHS)`.
129
+ * @param assignExpr
130
+ * the full assignment expression, for `code`, `line` properties
131
+ * @param assignOp
132
+ * the final assignment operator name, cf. [[Operators ]]
133
+ * @param setterInfo
134
+ * the setter meta-data, cf. [[tryResolveSetterInvocation ]]
135
+ */
136
+ private def astForMemberAccessSetterAssignment (
137
+ assignExpr : DotNetNodeInfo ,
138
+ lhs : DotNetNodeInfo ,
139
+ assignOp : String ,
140
+ rhs : DotNetNodeInfo ,
141
+ setterInfo : (CSharpMethod , String )
142
+ ): Seq [Ast ] = {
143
+ val (setterMethod, setterBaseType) = setterInfo
144
+ val receiver = if (setterMethod.isStatic) {
145
+ None
146
+ } else {
147
+ val baseNode = createDotNetNodeInfo(lhs.json(ParserKeys .Expression ))
148
+ astForNode(baseNode).headOption
149
+ }
150
+ val rhsAst = lowerSetterAssignmentRhs(assignExpr, assignOp, setterInfo, receiver, rhs)
151
+
152
+ createInvocationAst(
153
+ assignExpr,
154
+ setterMethod.name,
155
+ rhsAst,
156
+ receiver,
157
+ Some (setterMethod),
158
+ Some (setterBaseType)
159
+ ) :: Nil
160
+ }
161
+
162
+ /** Lowers assignments such as `P = RHS` and `P += RHS` with `P` an identifier denoting a setter property into calls
163
+ * `set_P(RHS)` and `set_P(get_P() + RHS)`, respectively.
164
+ * @param assignExpr
165
+ * the full assignment expression, for `code`, `line` properties.
166
+ * @param assignOp
167
+ * the final assignment operator name, cf. [[Operators ]]
168
+ * @param setterInfo
169
+ * the setter meta-data, cf. [[tryResolveSetterInvocation ]]
170
+ */
171
+ private def astForIdentifierSetterAssignment (
172
+ assignExpr : DotNetNodeInfo ,
173
+ lhs : DotNetNodeInfo ,
174
+ assignOp : String ,
175
+ rhs : DotNetNodeInfo ,
176
+ setterInfo : (CSharpMethod , String )
177
+ ): Seq [Ast ] = {
178
+ val (setterMethod, setterBaseType) = setterInfo
179
+ val receiver = Option .when(! setterMethod.isStatic)(astForThisReceiver(lhs, scope.surroundingTypeDeclFullName))
180
+ val rhsAst = lowerSetterAssignmentRhs(assignExpr, assignOp, setterInfo, receiver, rhs)
181
+
182
+ createInvocationAst(
183
+ assignExpr,
184
+ setterMethod.name,
185
+ rhsAst,
186
+ receiver,
187
+ Some (setterMethod),
188
+ Some (setterBaseType)
189
+ ) :: Nil
190
+ }
130
191
131
- createInvocationAst(
132
- assignExpr,
133
- setterMethod.name,
134
- rhsAst,
135
- receiver,
136
- Some (setterMethod),
137
- Some (setterBaseType)
138
- ) :: Nil
192
+ /** Lowers assignments such as `x.P = RHS` and `P += RHS` where `P` denotes a setter property into a call
193
+ * `x.set_P(RHS)` and `set_P(get_P() + RHS)`, respectively.
194
+ *
195
+ * @param assignExpr
196
+ * the full assignment expr, for `code`, `line` properties
197
+ * @param setterInfo
198
+ * the setter meta-data, cf. [[tryResolveSetterInvocation ]]
199
+ * @param assignOp
200
+ * the final assignment operator name, cf. [[Operators ]]
201
+ */
202
+ private def astForSetterAssignmentExpression (
203
+ assignExpr : DotNetNodeInfo ,
204
+ setterInfo : (CSharpMethod , String ),
205
+ lhs : DotNetNodeInfo ,
206
+ assignOp : String ,
207
+ rhs : DotNetNodeInfo
208
+ ): Seq [Ast ] = {
209
+ lhs.node match {
210
+ case SimpleMemberAccessExpression =>
211
+ astForMemberAccessSetterAssignment(assignExpr, lhs, assignOp, rhs, setterInfo)
212
+ case IdentifierName => astForIdentifierSetterAssignment(assignExpr, lhs, assignOp, rhs, setterInfo)
139
213
case _ =>
140
214
logger.warn(s " Unsupported setter assignment: ${code(assignExpr)}" )
141
215
Nil
142
216
}
143
217
}
144
218
219
+ /** Lowers arbitrary assignment `LHS = RHS`, `LHS += RHS`, etc. expressions.
220
+ * @param assignExpr
221
+ * the full assignment, for `code`, `line` properties
222
+ * @param assignOp
223
+ * the final assignment operator name, cf. [[Operators ]]
224
+ */
145
225
private def astForAssignmentExpression (
146
226
assignExpr : DotNetNodeInfo ,
147
- lhsNode : DotNetNodeInfo ,
148
- opName : String ,
149
- rhsNode : DotNetNodeInfo
227
+ lhs : DotNetNodeInfo ,
228
+ assignOp : String ,
229
+ rhs : DotNetNodeInfo
150
230
): Seq [Ast ] = {
151
- tryResolveSetterInvocation(lhsNode ) match {
152
- case Some (setterInfo) => astForSetterAssignmentExpression(assignExpr, setterInfo, lhsNode, opName, rhsNode )
153
- case None => astForRegularAssignmentExpression(assignExpr, lhsNode, opName, rhsNode )
231
+ tryResolveSetterInvocation(lhs ) match {
232
+ case Some (setterInfo) => astForSetterAssignmentExpression(assignExpr, setterInfo, lhs, assignOp, rhs )
233
+ case None => astForRegularAssignmentExpression(assignExpr, lhs, assignOp, rhs )
154
234
}
155
235
}
156
236
157
237
private def astForRegularAssignmentExpression (
158
238
assignExpr : DotNetNodeInfo ,
159
239
lhs : DotNetNodeInfo ,
160
- opName : String ,
240
+ assignOp : String ,
161
241
rhs : DotNetNodeInfo
162
242
): Seq [Ast ] = {
163
- astForRegularBinaryExpression(assignExpr, lhs, opName , rhs)
243
+ astForRegularBinaryExpression(assignExpr, lhs, assignOp , rhs)
164
244
}
165
245
166
246
private def astForParenthesizedExpression (parenExpr : DotNetNodeInfo ): Seq [Ast ] = {
@@ -252,13 +332,18 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {
252
332
}
253
333
}
254
334
335
+ /** @param binaryExpr
336
+ * the full binary expression, for `code`, `line`, etc.
337
+ * @param operatorName
338
+ * the final operator name, cf. [[Operators ]]
339
+ */
255
340
private def astForRegularBinaryExpression (
256
341
binaryExpr : DotNetNodeInfo ,
257
- lhsNode : DotNetNodeInfo ,
342
+ lhs : DotNetNodeInfo ,
258
343
operatorName : String ,
259
- rhsNode : DotNetNodeInfo
344
+ rhs : DotNetNodeInfo
260
345
): Seq [Ast ] = {
261
- val args = astForOperand(lhsNode ) ++: astForOperand(rhsNode )
346
+ val args = astForOperand(lhs ) ++: astForOperand(rhs )
262
347
val typeFullName = fixedTypeOperators.get(operatorName).orElse(Some (getTypeFullNameFromAstNode(args)))
263
348
val callNode = operatorCallNode(binaryExpr, operatorName, typeFullName)
264
349
callAst(callNode, args) :: Nil
0 commit comments