/**
  * 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;
  }