/**
   * Some extra information is needed per variable inside the snippet to generate the parts. This
   * information is wrapped in an extra
   *
   * <p>Build the set of template wrappers for the input variables of the loop
   *
   * @return
   */
  public List<TemplateInputVariable> getTemplateAccessesWrappers() {
    // TODO: Unit test for this
    if (templateAccessesWrappers != null) return templateAccessesWrappers;

    ArrayList<TemplateInputVariable> result = new ArrayList<>();
    for (CtVariableAccess access : getAccesses()) {
      TemplateInputVariable var = new TemplateInputVariable();
      var.initialize(this, access);
      if (printer instanceof DefaultJavaPrettyPrinter) {
        var.setPrinter(new DefaultJavaPrettyPrinter(astElement.getFactory().getEnvironment()));
      } else var.setPrinter(new AJMHPrettyPrinter(this));
      result.add(var);
    }
    boolean canSerializeThiz =
        getPreconditions().checkTypeRef(getASTElement().getParent(CtClass.class).getReference());
    if (canSerializeThiz && getMustSerializeThiz()) {
      //            astElement.getFactory().Code().createVariableAccess()
      TemplateInputVariable thiz = new TemplateInputVariable();
      thiz.initializeAsThiz(this);
      if (printer instanceof DefaultJavaPrettyPrinter) {
        thiz.setPrinter(new DefaultJavaPrettyPrinter(astElement.getFactory().getEnvironment()));
      } else thiz.setPrinter(new AJMHPrettyPrinter(this));
      result.add(thiz);
    }
    templateAccessesWrappers = result;
    return result;
  }
 public Boolean getMustSerializeThiz() {
   if (mustSerializeThiz == null) {
     List<CtInvocation> invocations =
         astElement.getElements(new TypeFilter<CtInvocation>(CtInvocation.class));
     for (CtInvocation inv : invocations) {
       if (isImplicitThiz(inv)) {
         mustSerializeThiz = true;
         return true;
       }
     }
     mustSerializeThiz = false;
   }
   return mustSerializeThiz;
 }
 public String getCode() {
   if (astElement != null) {
     try {
       if (printer == null) return astElement.toString();
       printer.reset();
       printer.scan(astElement);
       return printer.toString();
     } catch (NullPointerException ex) {
       throw new NullPointerException(
           "Unable to get the code. Code field was empty and astElement.toString() throw null");
     }
   }
   return code;
 }
  /**
   * Type of the benchmarks method for this snippet. This is 'void' by default.
   *
   * <p>The benchmark method type must be the same that the one
   */
  public String getBenchMethodReturnType() {
    if (benchMethodReturnType == null) {
      if (astElement != null) {
        List<CtReturn> rets = astElement.getElements(new TypeFilter<CtReturn>(CtReturn.class));
        if (rets != null && rets.size() > 0 && rets.get(0).getReturnedExpression() != null) {
          CtTypeReference t = rets.get(0).getReturnedExpression().getType();
          if (t.isAnonymous() || t.getQualifiedName().equals("<nulltype>"))
            benchMethodReturnType = "Object";
          else benchMethodReturnType = t.getQualifiedName();
        }
      }
    }

    return benchMethodReturnType == null ? "void" : benchMethodReturnType;
  }
 /** Sets the printer to be de default printer */
 public void setPrinterToDefault() {
   this.printer = new DefaultJavaPrettyPrinter(astElement.getFactory().getEnvironment());
   for (TemplateInputVariable v : getTemplateAccessesWrappers()) {
     v.setPrinter(new DefaultJavaPrettyPrinter(astElement.getFactory().getEnvironment()));
   }
 }
  /**
   * Resolves all the variables used by the snippet. The ones which are initialized and the ones
   * which are not
   *
   * @return True if the context was extracted successfully
   */
  private boolean resolveDataContext(CtStatement statement) {

    needsInitialization = false;

    // Check some preconditions needed for the processor to run:
    // All variable access made inside the statement
    List<CtVariableAccess> access = statement.getElements(new TypeFilter<>(CtVariableAccess.class));

    if (statement.getElements(new TypeFilter<>(CtThisAccess.class)).size() > 0) {
      mustSerializeThiz =
          new Preconditions().checkTypeRef(statement.getParent(CtClass.class).getReference());
    }

    initialized = new HashSet<>();

    // Get all THIZ field access from all invocations used in the element
    HashSet<CtInvocation> visited = new HashSet<>();
    Stack<CtInvocation> invStack = new Stack<>();
    invStack.addAll(statement.getElements(new TypeFilter<>(CtInvocation.class)));
    while (!invStack.empty()) {
      CtInvocation inv = invStack.pop();
      if (!visited.contains(inv)) {
        visited.add(inv);
        CtBlock b;
        try {
          b = inv.getExecutable().getDeclaration().getBody();
        } catch (NullPointerException ex) {
          b = null;
        }
        if (visibility(inv) != PUBLIC && b != null) {
          for (CtFieldAccess ta :
              b.getElements(new TypeFilter<CtFieldAccess>(CtFieldAccess.class))) {
            if (ta.getTarget() instanceof CtThisAccess || ta.getTarget() == null) {
              access.add(ta);
              // initialized.add(ta);
            }
          }
          for (CtInvocation i : b.getElements(new TypeFilter<CtInvocation>(CtInvocation.class))) {
            if (!visited.contains(i)) invStack.push(i);
          }
        }
      }
    }

    access = cleanRepeatedAccesses(access);
    setAccesses(access);

    // Find initialized variables of allowed types
    ControlFlowBuilder v = new ControlFlowBuilder();
    CtMethod m = statement.getParent(CtMethod.class);
    if (m == null) return false;
    m.accept(v);
    ControlFlowGraph g = v.getResult();
    g.simplify();
    try {
      InitializedVariables vars = new InitializedVariables();
      vars.run(ControlFlowBuilder.firstNode(g, statement));

      for (CtVariableAccess a : access) {
        // A variable must be initialized if is local and is not a serializable field
        // Also if is not a constant. Constant get declared in the body of the microbenchmark
        if (isInitialized(a, statement, vars) && !isAConstant(a)) initialized.add(a);
      }
    } catch (NotFoundException e) {
      return false;
    } catch (StackOverflowError e) {
      System.out.print(g.toGraphVisText());
      throw e;
    }

    needsInitialization = initialized.size() > 0;
    if (access.size() <= 0) return true;

    int i = 0;
    int replaced = 0;
    do {
      if (i == 0) replaced = 0;
      CtVariableAccess a = access.get(i);
      if (canBeReplacedByTarget(a)) {
        CtVariableAccess targetOfA = null;
        CtTargetedExpression ta = (CtTargetedExpression) a;
        if (ta.getTarget() != null) {
          if (ta.getTarget() instanceof CtVariableAccess) {
            targetOfA = (CtVariableAccess) ta.getTarget();
          } else if (ta.getTarget() instanceof CtThisAccess) {
            mustSerializeThiz = true;
          }
        } else {
          mustSerializeThiz = true;
        }
        if (targetOfA != null) {
          if (!access.contains(targetOfA)) access.add(targetOfA);
          if (initialized.contains(a) && !initialized.contains(targetOfA))
            initialized.add(targetOfA);
        }
        access.remove(a);
        if (initialized.contains(a)) initialized.remove(a);
        replaced++;
      } else i++;
      if (i >= access.size()) i = 0;
    } while (replaced > 0 || i != 0);
    return true;
  }
 public int getLineNumber() {
   if (astElement != null) lineNumber = astElement.getPosition().getLine();
   return lineNumber;
 }
 public String getClassName() {
   if (astElement != null)
     className = astElement.getPosition().getCompilationUnit().getMainType().getQualifiedName();
   return className;
 }