private static JavaAstScanner create(
     JavaConfiguration conf, @Nullable VisitorsBridge visitorsBridge) {
   JavaAstScanner astScanner = new JavaAstScanner(JavaParser.createParser(conf.getCharset()));
   if (visitorsBridge != null) {
     visitorsBridge.setCharset(conf.getCharset());
     visitorsBridge.setJavaVersion(conf.javaVersion());
     astScanner.setVisitorBridge(visitorsBridge);
   }
   return astScanner;
 }
public class ClassTreeImplTest {
  private final ActionParser p = JavaParser.createParser(StandardCharsets.UTF_8);

  private CompilationUnitTree createTree(String code) {
    CompilationUnitTree compilationUnitTree = (CompilationUnitTree) p.parse(code);
    SemanticModel.createFor(compilationUnitTree, Lists.<File>newArrayList());
    return compilationUnitTree;
  }

  @Test
  public void getLine() {
    CompilationUnitTree tree = createTree("class A {\n" + "A a = new A() {};" + "\n}");
    ClassTree classTree = (ClassTree) tree.types().get(0);
    assertThat(((JavaTree) classTree).getLine()).isEqualTo(1);
    // get line of anonymous class
    NewClassTree newClassTree =
        (NewClassTree) ((VariableTree) classTree.members().get(0)).initializer();
    assertThat(((JavaTree) newClassTree.classBody()).getLine()).isEqualTo(2);
  }
}
public class ReassignmentFinderTest {

  private final ActionParser<Tree> p = JavaParser.createParser(Charsets.UTF_8);

  @Test
  public void parameter() throws Exception {
    String code = newCode("int foo(int a) {", "  return a;", "}");

    MethodTree method = methodTree(code);
    List<StatementTree> statements = method.block().body();
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, null);
  }

  @Test
  public void parameter_with_usage() throws Exception {
    String code = newCode("int foo(boolean test) {", "  if (test) {}", "  return test;", "}");

    MethodTree method = methodTree(code);
    List<StatementTree> statements = method.block().body();
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, null);
  }

  @Test
  public void declaration() throws Exception {
    String code = newCode("int foo() {", "  int a = 0;", "  return a;", "}");

    List<StatementTree> statements = methodBody(code);
    ExpressionTree aDeclarationInitializer =
        initializerFromVariableDeclarationStatement(statements.get(0));
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, aDeclarationInitializer);
  }

  @Test
  public void unknown_variable() throws Exception {
    String code = newCode("int foo() {", "  return a;", "}");

    List<StatementTree> statements = methodBody(code);
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, null);
  }

  @Test
  public void array_declaration() throws Exception {
    String code =
        newCode("int foo() {", "  int a[] = new int[42];", "  a[0] = 42;", "  return a;", "}");

    List<StatementTree> statements = methodBody(code);
    ExpressionTree arrayAssignmentExpression =
        initializerFromVariableDeclarationStatement(statements.get(0));
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, arrayAssignmentExpression);
  }

  @Test
  public void assignement() throws Exception {
    String code = newCode("int foo() {", "  int a;", "  a = 0;", "  return a;", "}");

    List<StatementTree> statements = methodBody(code);
    ExpressionTree aAssignmentExpression = assignementExpressionFromStatement(statements.get(1));
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, aAssignmentExpression);
  }

  @Test
  public void assignement_with_other_variable() throws Exception {
    String code =
        newCode("int foo() {", "  int a;", "  int b;", "  a = 0;", "  b = 0;", "  return a;", "}");

    List<StatementTree> statements = methodBody(code);
    ExpressionTree aAssignmentExpression = assignementExpressionFromStatement(statements.get(2));
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, aAssignmentExpression);
  }

  @Test
  public void last_assignement() throws Exception {
    String code = newCode("int foo() {", "  int a;", "  a = 0;", "  a = 1;", "  return a;", "}");

    List<StatementTree> statements = methodBody(code);
    ExpressionTree secondAssignment = assignementExpressionFromStatement(statements.get(2));
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, secondAssignment);
  }

  @Test
  public void last_assignement_on_same_line() throws Exception {
    String code = newCode("int foo() {", "  int a;", "  a = 0;", "  a = 1; return a;", "}");

    List<StatementTree> statements = methodBody(code);
    ExpressionTree secondAssignment = assignementExpressionFromStatement(statements.get(2));
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, secondAssignment);
  }

  @Test
  public void outside_method() throws Exception {
    String code = newCode("int b;", "int foo() {", "  return b;", "}");

    ClassTree classTree = classTree(code);
    List<StatementTree> statements = ((MethodTree) classTree.members().get(1)).block().body();
    ExpressionTree variableDeclaration =
        ((VariableTree) (classTree.members().get(0))).initializer();
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, variableDeclaration);
  }

  @Test
  public void ignore_assignation_after_starting_point() throws Exception {
    String code = newCode("int foo() {", "  int b = 0;", "  doSomething(b);", "  b = 1;", "}");

    List<StatementTree> statements = methodBody(code);
    Tree expectedVariableDeclaration =
        initializerFromVariableDeclarationStatement(statements.get(0));
    MethodInvocationTree startingPoint =
        (MethodInvocationTree) ((ExpressionStatementTree) statements.get(1)).expression();
    Symbol searchedVariable = ((IdentifierTree) startingPoint.arguments().get(0)).symbol();
    assertThatLastReassignmentsOfVariableIsEqualTo(
        searchedVariable, startingPoint, expectedVariableDeclaration);
  }

  @Test
  public void ignore_assignation_after_starting_point_same_line() throws Exception {
    String code = newCode("int foo() {", "  int b = 0;", "  doSomething(b); b = 1;", "}");

    List<StatementTree> statements = methodBody(code);
    Tree expectedVariableDeclaration =
        initializerFromVariableDeclarationStatement(statements.get(0));
    MethodInvocationTree startingPoint =
        (MethodInvocationTree) ((ExpressionStatementTree) statements.get(1)).expression();
    Symbol searchedVariable = ((IdentifierTree) startingPoint.arguments().get(0)).symbol();
    assertThatLastReassignmentsOfVariableIsEqualTo(
        searchedVariable, startingPoint, expectedVariableDeclaration);
  }

  private static void assertThatLastReassignmentsOfVariableIsEqualTo(
      Symbol searchedVariable, Tree startingPoint, Tree expectedVariableDeclaration) {
    assertThat(
            ReassignmentFinder.getClosestReassignmentOrDeclarationExpression(
                startingPoint, searchedVariable))
        .isEqualTo(expectedVariableDeclaration);
  }

  @Test
  public void known_limitation() throws Exception {
    String code =
        newCode(
            "int foo(boolean test) {",
            "  int a;",
            "  if (test) {",
            "    a = 0;",
            "  } else {",
            "    a = 1;", // Should have returned both thenAssignment and elseAssignment. CFG?
            "  }",
            "  return a;",
            "}");

    List<StatementTree> statements = methodBody(code);
    StatementTree elseAssignment =
        ((BlockTree) ((IfStatementTree) statements.get(1)).elseStatement()).body().get(0);
    ExpressionTree expression = assignementExpressionFromStatement(elseAssignment);
    assertThatLastReassignmentsOfReturnedVariableIsEqualTo(statements, expression);
  }

  private static void assertThatLastReassignmentsOfReturnedVariableIsEqualTo(
      List<StatementTree> statements, ExpressionTree target) {
    assertThat(getLastReassignment(statements)).isEqualTo(target);
  }

  private static Tree getLastReassignment(List<StatementTree> statements) {
    return ReassignmentFinder.getClosestReassignmentOrDeclarationExpression(
        statements.get(statements.size() - 1),
        variableFromLastReturnStatement(statements).symbol());
  }

  private static IdentifierTree variableFromLastReturnStatement(List<StatementTree> statements) {
    return (IdentifierTree)
        ((ReturnStatementTree) statements.get(statements.size() - 1)).expression();
  }

  private static ExpressionTree assignementExpressionFromStatement(StatementTree statement) {
    return ((AssignmentExpressionTree) ((ExpressionStatementTree) statement).expression())
        .expression();
  }

  private static ExpressionTree initializerFromVariableDeclarationStatement(Tree statement) {
    return ((VariableTree) statement).initializer();
  }

  private ClassTree classTree(String classBody) {
    CompilationUnitTree compilationUnitTree = (CompilationUnitTree) p.parse(classBody);
    SemanticModel.createFor(compilationUnitTree, Lists.<File>newArrayList());
    return (ClassTree) compilationUnitTree.types().get(0);
  }

  private MethodTree methodTree(String classBody) {
    ClassTree firstType = classTree(classBody);
    return (MethodTree) firstType.members().get(0);
  }

  private List<StatementTree> methodBody(String code) {
    return methodTree(code).block().body();
  }

  private static String newCode(String... lines) {
    String lineSeparator = System.lineSeparator();
    StringBuilder sb = new StringBuilder("class A {").append(lineSeparator);
    for (String string : lines) {
      sb.append(string).append(lineSeparator);
    }
    return sb.append("}").append(lineSeparator).toString();
  }
}
public class AccessorsUtilsTest {

  private final ActionParser p = JavaParser.createParser(Charsets.UTF_8);

  @Test
  public void method_badly_named_is_not_accessor() {
    assertThat(isAccessor("class T { private int a; int foo() { return a; } }")).isFalse();
    assertThat(isAccessor("class T { private int a; int foo(int a) { this.a = a; } }")).isFalse();
  }

  @Test
  public void method_named_properly_is_getter() {
    assertThat(isAccessor("class T { private int a; public int getA() { return a; } }")).isTrue();
  }

  @Test
  public void method_named_properly_is_setter() {
    assertThat(isAccessor("class T { private int a; public void setA(int a) { this.a = a; } }"))
        .isTrue();
  }

  @Test
  public void boolean_method_named_properly_is_getter() {
    assertThat(isAccessor("class T { private  boolean a; public boolean isA() { return a; } }"))
        .isTrue();
  }

  @Test
  public void boolean_method_named_properly_is_getter_if_return_type_is_boolean() {
    assertThat(isAccessor("class T { private  int a; int isA() { return a; } }")).isFalse();
  }

  @Test
  public void is_getter_if_has_one_return_statement() {
    assertThat(isAccessor("class T { private boolean a; public boolean isA() { a=!a;return a; } }"))
        .isFalse();
    assertThat(isAccessor("class T { private int a; public int getA() { a++;return a; } }"))
        .isFalse();
    assertThat(isAccessor("class T { private boolean a; public boolean isA() { return a; } }"))
        .isTrue();
    assertThat(isAccessor("class T { private int a; public int getA() { return a; } }")).isTrue();
    assertThat(isAccessor("class T { private int a; public void getA() { a++; } }")).isFalse();
  }

  @Test
  public void constructor_is_not_accessor() {
    assertThat(isAccessor("class getA {private int a; public getA() {} }")).isFalse();
  }

  @Test
  public void getter_should_reference_private_property() {
    assertThat(isAccessor("class T { private boolean a; public boolean isA() { return true;} }"))
        .isFalse();
    assertThat(isAccessor("class T { boolean a; public boolean isA() { return a;} }")).isFalse();
    assertThat(isAccessor("class T { private boolean a; public boolean isA() { return a;} }"))
        .isTrue();
    assertThat(isAccessor("class T { private int a; public int getA() { return 1; } }")).isFalse();
    assertThat(isAccessor("class T { int a; public int getA() { return a; } }")).isFalse();
    assertThat(isAccessor("class T { int a; public void getA() { return; } }")).isFalse();
    assertThat(isAccessor("class T { private int a; public int getA() { return a; } }")).isTrue();
  }

  @Test
  public void getter_should_have_no_parameters() {
    assertThat(
            isAccessor("class T { private boolean a; public boolean isA(boolean b) { return a;} }"))
        .isFalse();
    assertThat(isAccessor("class T { private int a; public int getA(int b) { return 1; } }"))
        .isFalse();
  }

  @Test
  public void method_with_no_body_is_not_getter_nor_setter() {
    assertThat(isAccessor("interface T { boolean isA(); }")).isFalse();
  }

  @Test
  public void setter_should_have_one_parameter() {
    assertThat(isAccessor("class T { private int a; public void setA() { this.a = a; } }"))
        .isFalse();
    assertThat(
            isAccessor("class T { private int a; public void setA(int a, int b) { this.a = a; } }"))
        .isFalse();
  }

  @Test
  public void setter_should_have_void_return_type() {
    assertThat(isAccessor("class T { private int a; public int setA(int a) { return a; } }"))
        .isFalse();
  }

  @Test
  public void setter_body_is_an_assignement_statement_referencing_private_var() {
    assertThat(isAccessor("class T { private int a; public void setA(int a) { a++; } }")).isFalse();
    assertThat(isAccessor("class T { private int a; public void setA(int a) { b=0; } }")).isFalse();
    assertThat(isAccessor("class T { private int a; public void setA(int a) { b = a; } }"))
        .isFalse();
    // limitation
    assertThat(isAccessor("class T { private int a; public void setA(int a) { a = b; } }"))
        .isTrue();
    assertThat(isAccessor("class T { private int a; public void setA(int a) { this.a = b; } }"))
        .isTrue();
  }

  @Test
  public void getter_using_this_are_not_accessor() throws Exception {
    // FIXME : those getters should be considered as accessors
    assertThat(isAccessor("class T { private int a; public int getA() { return this.a; } }"))
        .isFalse();
  }

  @Test
  public void accessor_should_be_public() {
    assertThat(isAccessor("class T { private int a; void setA(int a) { this.a=a; } }")).isFalse();
    assertThat(isAccessor("class T { private int a; public void setA(int a) { this.a=a; } }"))
        .isTrue();
  }

  private boolean isAccessor(String code) {
    ClassTree classTree = parseClass(code);
    return AccessorsUtils.isAccessor(classTree, extractMethod(classTree));
  }

  private ClassTree parseClass(String code) {
    return extractClass((CompilationUnitTree) p.parse(code));
  }

  private ClassTree extractClass(CompilationUnitTree cut) {
    return (ClassTree) cut.types().get(0);
  }

  private MethodTree extractMethod(ClassTree classTree) {
    for (Tree tree : classTree.members()) {
      if (tree.is(Tree.Kind.METHOD) || tree.is(Tree.Kind.CONSTRUCTOR)) {
        return (MethodTree) tree;
      }
    }
    return null;
  }
}