|
16 | 16 | import liquidjava.utils.constants.Ops; |
17 | 17 | import liquidjava.utils.constants.Types; |
18 | 18 | import liquidjava.rj_language.Predicate; |
| 19 | +import liquidjava.rj_language.ast.BinaryExpression; |
| 20 | +import liquidjava.rj_language.ast.Expression; |
| 21 | +import liquidjava.rj_language.ast.GroupExpression; |
19 | 22 | import org.apache.commons.lang3.NotImplementedException; |
20 | 23 | import spoon.reflect.code.BinaryOperatorKind; |
21 | 24 | import spoon.reflect.code.CtAssignment; |
|
26 | 29 | import spoon.reflect.code.CtInvocation; |
27 | 30 | import spoon.reflect.code.CtLiteral; |
28 | 31 | import spoon.reflect.code.CtLocalVariable; |
| 32 | +import spoon.reflect.code.CtOperatorAssignment; |
29 | 33 | import spoon.reflect.code.CtReturn; |
30 | 34 | import spoon.reflect.code.CtUnaryOperator; |
31 | 35 | import spoon.reflect.code.CtVariableRead; |
@@ -94,6 +98,18 @@ public <T> void getBinaryOpRefinements(CtBinaryOperator<T> operator) throws LJEr |
94 | 98 | // TODO ADD TYPES |
95 | 99 | } |
96 | 100 |
|
| 101 | + /** |
| 102 | + * Builds the refinement for a operator assignment. Java operator assignments such as {@code x += y} are modeled as |
| 103 | + * {@code x = x + y}; the returned predicate refines the assigned value as {@code _ == current(x) <op> rhs}. |
| 104 | + */ |
| 105 | + public Predicate getOperatorAssignmentRefinement(String assignedName, CtOperatorAssignment<?, ?> assignment) |
| 106 | + throws LJError { |
| 107 | + Predicate left = getCurrentVariableValue(assignedName); |
| 108 | + Predicate right = getOperatorAssignmentRefinement(assignment.getAssignment()); |
| 109 | + Predicate operation = Predicate.createOperation(left, getOperatorFromKind(assignment.getKind()), right); |
| 110 | + return Predicate.createEquals(Predicate.createVar(Keys.WILDCARD), operation); |
| 111 | + } |
| 112 | + |
97 | 113 | /** |
98 | 114 | * Finds and adds refinement metadata to the unary operation |
99 | 115 | * |
@@ -280,6 +296,48 @@ private Predicate getOperationRefinementFromExternalLib(CtInvocation<?> inv) thr |
280 | 296 | return new Predicate(); |
281 | 297 | } |
282 | 298 |
|
| 299 | + /** |
| 300 | + * Returns the latest symbolic value for a variable |
| 301 | + */ |
| 302 | + private Predicate getCurrentVariableValue(String name) { |
| 303 | + Optional<VariableInstance> variableInstance = rtc.getContext().getLastVariableInstance(name); |
| 304 | + return Predicate.createVar(variableInstance.map(VariableInstance::getName).orElse(name)); |
| 305 | + } |
| 306 | + |
| 307 | + /** |
| 308 | + * Converts a operator assignment into an arithmetic predicate operand |
| 309 | + */ |
| 310 | + private Predicate getOperatorAssignmentRefinement(CtExpression<?> element) throws LJError { |
| 311 | + if (element instanceof CtVariableRead<?> variableRead) { |
| 312 | + String name = variableRead.getVariable().getSimpleName(); |
| 313 | + if (variableRead instanceof CtFieldRead<?>) |
| 314 | + name = String.format(Formats.THIS, name); |
| 315 | + return getCurrentVariableValue(name); |
| 316 | + } else if (element instanceof CtBinaryOperator<?> binaryOperator) { |
| 317 | + Predicate left = getOperatorAssignmentRefinement(binaryOperator.getLeftHandOperand()); |
| 318 | + Predicate right = getOperatorAssignmentRefinement(binaryOperator.getRightHandOperand()); |
| 319 | + return Predicate.createOperation(left, getOperatorFromKind(binaryOperator.getKind()), right); |
| 320 | + } else if (element instanceof CtLiteral<?> literal) { |
| 321 | + if (literal.getValue() == null) |
| 322 | + throw new CustomError("Null literals are not supported", literal.getPosition()); |
| 323 | + return new Predicate(literal.getValue().toString(), element); |
| 324 | + } |
| 325 | + // unwrap wildcard equality: _ == expr -> expr |
| 326 | + Predicate refinement = rtc.getRefinement(element); |
| 327 | + Expression expression = unwrapGroupExpression(refinement.getExpression()); |
| 328 | + if (expression instanceof BinaryExpression binaryExpression && Ops.EQ.equals(binaryExpression.getOperator()) |
| 329 | + && Keys.WILDCARD.equals(binaryExpression.getFirstOperand().toString())) { |
| 330 | + return new Predicate(binaryExpression.getSecondOperand()); |
| 331 | + } |
| 332 | + return refinement; |
| 333 | + } |
| 334 | + |
| 335 | + private Expression unwrapGroupExpression(Expression expression) { |
| 336 | + while (expression instanceof GroupExpression groupExpression) |
| 337 | + expression = groupExpression.getExpression(); |
| 338 | + return expression; |
| 339 | + } |
| 340 | + |
283 | 341 | /** |
284 | 342 | * Retrieves the refinements for the variable write inside unary operation |
285 | 343 | * |
|
0 commit comments