/** * One var can be pointed by multiples accesses. This method leaves only one access per variable * in the list */ private List<CtVariableAccess> cleanRepeatedAccesses(List<CtVariableAccess> allAccess) { // Have only one access per variable HashSet<String> varSignatures = new HashSet<>(); List<CtVariableAccess> access = new ArrayList<>(); for (CtVariableAccess a : allAccess) { if (isFieldOfPrimitiveArray(a)) continue; String signature = ""; if (a instanceof CtFieldAccess && ((CtFieldAccess) a).getTarget() != null) signature = ((CtFieldAccess) a).getTarget().toString(); signature += a.getVariable().getSimpleName() + a.getVariable().getClass().getSimpleName(); if (!varSignatures.contains(signature)) { varSignatures.add(signature); access.add(a); } } varSignatures.clear(); return access; }
@Override public <T> void visitCtUnaryOperator(CtUnaryOperator<T> operator) { for (CtVariableAccess a : accessOfExpression(operator)) { // Add cyclic dependencies to external variables if (declaredInsideBlock.contains(a.getVariable())) { remove(operator); return; } } }
@Override public <T, A extends T> void visitCtOperatorAssignement(CtOperatorAssignment<T, A> assignment) { for (CtVariableAccess a : accessOfExpression(assignment.getAssigned())) { // Add cyclic dependencies if (!declaredInsideBlock.contains(a.getVariable())) { remove(assignment); return; } } }
/** * Indicates that contains operation assignment over variables non local to the element * * @param element * @return */ private boolean containNonLocalOperatorAssignment(CtElement element) { // Handling operators assignment for (CtOperatorAssignment op : element.getElements(new TypeFilter<CtOperatorAssignment>(CtOperatorAssignment.class))) { for (CtVariableAccess a : accessOfExpression(op.getAssigned())) { // Add cyclic dependencies if (!declaredInsideBlock.contains(a.getVariable())) return true; } } return false; }
/** * Indicates if the element contains unary operators acting on variables declared outside the * block being degraded * * @param element Element to inspect * @return True if contains */ private boolean containsNonLocalUnaryOperators(CtElement element) { // Handling unary operators for (CtUnaryOperator op : element.getElements(new TypeFilter<CtUnaryOperator>(CtUnaryOperator.class))) { for (CtVariableAccess a : accessOfExpression(op)) { // We don't care about cyclic dependencies to vars declared inside the block being degraded if (!declaredInsideBlock.contains(a.getVariable())) return true; } } return false; }
/** * Indicate if the statement contains a mutable expression * * <p>A mutability expression is an expression that assigns value to a variable in the left side * using that variable also in the right side, like this: * * <p>a = a * b * * <p>or like this: c = a * 2 a = c + b * * <p> * * <p>Also, all unary operators and are mutable: a--; a++; * * @param statement Statement to check whether is a mutability expression * @return True if it is a mutability expression */ private Mutability mutability(CtElement statement) { Mutability result = Mutability.ERASABLE; if (statement instanceof CtAssignment) { CtAssignment e = (CtAssignment) statement; List<CtVariableAccess> left = accessOfLeftExpression(e.getAssigned()); for (CtVariableAccess access : left) { CtVariableReference ref = access.getVariable(); try { if (!declaredInsideBlock.contains(ref) && cycleDetector.detectCyclesContainingVertex(ref)) { return Mutability.IMMUTABLE; } } catch (IllegalArgumentException ex) { continue; } } } if (containNonLocalOperatorAssignment(statement)) return Mutability.IMMUTABLE; else if (containsNonLocalUnaryOperators(statement)) return Mutability.REPLACEABLE; else return Mutability.ERASABLE; }