// RUN: %check_clang_tidy %s readability-braces-around-statements %t

void do_something(const char *) {}

bool cond(const char *) {
  return false;
}

#define EMPTY_MACRO
#define EMPTY_MACRO_FUN()

void test() {
  if (cond("if0") /*comment*/) do_something("same-line");
  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: statement should be inside braces
  // CHECK-FIXES:   if (cond("if0") /*comment*/) { do_something("same-line");
  // CHECK-FIXES: }

  if (cond("if0.1"))
    do_something("single-line");
  // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("if0.1")) {
  // CHECK-FIXES: }

  if (cond("if1") /*comment*/)
    // some comment
    do_something("if1");
  // CHECK-MESSAGES: :[[@LINE-3]]:31: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("if1") /*comment*/) {
  // CHECK-FIXES: }
  if (cond("if2")) {
    do_something("if2");
  }
  if (cond("if3"))
    ;
  // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("if3")) {
  // CHECK-FIXES: }

  if (cond("if-else1"))
    do_something("if-else1");
  // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("if-else1")) {
  // CHECK-FIXES: } else {
  else
    do_something("if-else1 else");
  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: statement should be inside braces
  // CHECK-FIXES: }
  if (cond("if-else2")) {
    do_something("if-else2");
  } else {
    do_something("if-else2 else");
  }

  if (cond("if-else if-else1"))
    do_something("if");
  // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: statement should be inside braces
  // CHECK-FIXES: } else if (cond("else if1")) {
  else if (cond("else if1"))
    do_something("else if");
  // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: statement should be inside braces
  else
    do_something("else");
  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: statement should be inside braces
  // CHECK-FIXES: }
  if (cond("if-else if-else2")) {
    do_something("if");
  } else if (cond("else if2")) {
    do_something("else if");
  } else {
    do_something("else");
  }

  for (;;)
    do_something("for");
  // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: statement should be inside braces
  // CHECK-FIXES: for (;;) {
  // CHECK-FIXES-NEXT: do_something("for");
  // CHECK-FIXES-NEXT: }

  for (;;)
    ;
  // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: statement should be inside braces
  // CHECK-FIXES: for (;;) {
  // CHECK-FIXES-NEXT: ;
  // CHECK-FIXES-NEXT: }

  for (;;) {
    do_something("for-ok");
  }

  int arr[4] = {1, 2, 3, 4};
  for (int a : arr)
    do_something("for-range");
  // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: statement should be inside braces
  // CHECK-FIXES: for (int a : arr) {
  // CHECK-FIXES-NEXT: do_something("for-range");
  // CHECK-FIXES-NEXT: }
  for (int &assign : arr)
    assign = 7;
  // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: statement should be inside braces
  // CHECK-FIXES: for (int &assign : arr) {
  // CHECK-FIXES-NEXT: assign = 7;
  // CHECK-FIXES-NEXT: }
  for (int ok : arr) {
    do_something("for-range");
  }
  for (int NullStmt : arr)
    ;
  // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: statement should be inside braces
  // CHECK-FIXES: for (int NullStmt : arr) {
  // CHECK-FIXES-NEXT: ;
  // CHECK-FIXES-NEXT: }

  while (cond("while1"))
    do_something("while");
  // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: statement should be inside braces
  // CHECK-FIXES: while (cond("while1")) {
  // CHECK-FIXES: }
  while (cond("while2")) {
    do_something("while");
  }
  while (false)
    ;
  // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: statement should be inside braces
  // CHECK-FIXES: while (false) {
  // CHECK-FIXES: }

  do
    do_something("do1");
  while (cond("do1"));
  // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: statement should be inside braces
  // CHECK-FIXES: do {
  // CHECK-FIXES: } while (cond("do1"));
  do {
    do_something("do2");
  } while (cond("do2"));

  do
    ;
  while (false);
  // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: statement should be inside braces
  // CHECK-FIXES: do {
  // CHECK-FIXES: } while (false);

  if (cond("ifif1"))
    // comment
    if (cond("ifif2"))
      // comment
      /*comment*/ ; // comment
  // CHECK-MESSAGES: :[[@LINE-5]]:21: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-4]]:23: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("ifif1")) {
  // CHECK-FIXES: if (cond("ifif2")) {
  // CHECK-FIXES: }
  // CHECK-FIXES-NEXT: }

  if (cond("ifif3"))
    // comment1
    if (cond("ifif4")) {
      // comment2
      /*comment3*/; // comment4
    }
  // CHECK-MESSAGES: :[[@LINE-6]]:21: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("ifif3")) {
  // CHECK-FIXES-NEXT: // comment1
  // CHECK-FIXES-NEXT: if (cond("ifif4")) {
  // CHECK-FIXES-NEXT: // comment2
  // CHECK-FIXES-NEXT: /*comment3*/; // comment4
  // CHECK-FIXES-NEXT: }
  // CHECK-FIXES-NEXT: }

  if (cond("ifif5"))
    ; /* multi-line
        comment */
  // CHECK-MESSAGES: :[[@LINE-3]]:21: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("ifif5")) {
  // CHECK-FIXES: }/* multi-line

  if (1) while (2) if (3) for (;;) do ; while(false) /**/;/**/
  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-4]]:35: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-5]]:38: warning: statement should be inside braces
  // CHECK-FIXES: if (1) { while (2) { if (3) { for (;;) { do { ; } while(false) /**/;/**/
  // CHECK-FIXES-NEXT: }
  // CHECK-FIXES-NEXT: }
  // CHECK-FIXES-NEXT: }
  // CHECK-FIXES-NEXT: }

  int S;
  if (cond("assign with brackets"))
    S = {5};
  // CHECK-MESSAGES: :[[@LINE-2]]:36: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("assign with brackets")) {
  // CHECK-FIXES-NEXT: S = {5};
  // CHECK-FIXES-NEXT: }

  if (cond("assign with brackets 2"))
    S = {  5  } /* comment1 */ ; /* comment2 */
  // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("assign with brackets 2")) {
  // CHECK-FIXES-NEXT: S = {  5  } /* comment1 */ ; /* comment2 */
  // CHECK-FIXES-NEXT: }

  if (cond("return"))
    return;
  // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("return")) {
  // CHECK-FIXES-NEXT: return;
  // CHECK-FIXES-NEXT: }

  while (cond("break and continue")) {
    // CHECK-FIXES: while (cond("break and continue")) {
    if (true)
      break;
    // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: statement should be inside braces
    // CHECK-FIXES: {{^}}    if (true) {{{$}}
    // CHECK-FIXES-NEXT: {{^}}      break;{{$}}
    // CHECK-FIXES-NEXT: {{^ *}}}{{$}}
    if (false)
      continue;
    // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: statement should be inside braces
    // CHECK-FIXES: {{^}}    if (false) {{{$}}
    // CHECK-FIXES-NEXT: {{^}}      continue;{{$}}
    // CHECK-FIXES-NEXT: {{^ *}}}{{$}}
  } //end
  // CHECK-FIXES: } //end

  if (cond("decl 1"))
    int s;
  else
    int t;
  // CHECK-MESSAGES: :[[@LINE-4]]:22: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("decl 1")) {
  // CHECK-FIXES-NEXT: int s;
  // CHECK-FIXES-NEXT: } else {
  // CHECK-FIXES-NEXT: int t;
  // CHECK-FIXES-NEXT: }

  if (cond("decl 2"))
    int s = (5);
  else
    int t = (5);
  // CHECK-MESSAGES: :[[@LINE-4]]:22: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("decl 2")) {
  // CHECK-FIXES-NEXT: int s = (5);
  // CHECK-FIXES-NEXT: } else {
  // CHECK-FIXES-NEXT: int t = (5);
  // CHECK-FIXES-NEXT: }

  if (cond("decl 3"))
    int s = {6};
  else
    int t = {6};
  // CHECK-MESSAGES: :[[@LINE-4]]:22: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("decl 3")) {
  // CHECK-FIXES-NEXT: int s = {6};
  // CHECK-FIXES-NEXT: } else {
  // CHECK-FIXES-NEXT: int t = {6};
  // CHECK-FIXES-NEXT: }
}

void test_whitespace() {
  while(cond("preserve empty lines"))
    if(cond("using continue within if"))
      continue;


  test();

  // CHECK-MESSAGES: :[[@LINE-7]]:{{[0-9]+}}: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-7]]:{{[0-9]+}}: warning: statement should be inside braces
  // CHECK-FIXES: {{^}}  while(cond("preserve empty lines")) {{{$}}
  // CHECK-FIXES-NEXT: {{^}}    if(cond("using continue within if")) {{{$}}
  // CHECK-FIXES-NEXT: {{^      continue;$}}
  // The closing brace is added at beginning of line, clang-format can be
  // applied afterwards.
  // CHECK-FIXES-NEXT: {{^}$}}
  // CHECK-FIXES-NEXT: {{^}$}}
  // Following whitespace is assumed to not to belong to the else branch.
  // However the check is not possible with CHECK-FIXES-NEXT.
  // CHECK-FIXES: {{^}}  test();{{$}}

  if (cond("preserve empty lines"))
 
  
    int s;
   
    
  else
 
  
    int t;
   
    
  test();

  // CHECK-MESSAGES: :[[@LINE-14]]:{{[0-9]+}}: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-9]]:{{[0-9]+}}: warning: statement should be inside braces
  // CHECK-FIXES: {{^}}  if (cond("preserve empty lines")) {{{$}}
  // CHECK-FIXES-NEXT: {{^ $}}
  // CHECK-FIXES-NEXT: {{^  $}}
  // CHECK-FIXES-NEXT: {{^    int s;$}}
  // CHECK-FIXES-NEXT: {{^   $}}
  // CHECK-FIXES-NEXT: {{^    $}}
  // CHECK-FIXES-NEXT: {{^  } else {$}}
  // CHECK-FIXES-NEXT: {{^ $}}
  // CHECK-FIXES-NEXT: {{^  $}}
  // CHECK-FIXES-NEXT: {{^    int t;$}}
  // The closing brace is added at beginning of line, clang-format can be
  // applied afterwards.
  // CHECK-FIXES-NEXT: {{^}$}}
  // Following whitespace is assumed to not to belong to the else branch.
  // CHECK-FIXES-NEXT: {{^   $}}
  // CHECK-FIXES-NEXT: {{^    $}}
  // CHECK-FIXES-NEXT: {{^}}  test();{{$}}
}

int test_return_int() {
  if (cond("return5"))
    return 5;
  // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("return5")) {
  // CHECK-FIXES-NEXT: return 5;
  // CHECK-FIXES-NEXT: }

  if (cond("return{6}"))
    return {6};
  // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("return{6}")) {
  // CHECK-FIXES-NEXT: return {6};
  // CHECK-FIXES-NEXT: }

  // From https://bugs.llvm.org/show_bug.cgi?id=25970
  if (cond("25970")) return {25970};
  return {!25970};
  // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: statement should be inside braces
  // CHECK-FIXES: if (cond("25970")) { return {25970};
  // CHECK-FIXES-NEXT: }
  // CHECK-FIXES-NEXT: return {!25970};
}

void f(const char *p) {
  if (!p)
    f("\
");
} // end of f
// CHECK-MESSAGES: :[[@LINE-4]]:10: warning: statement should be inside braces
// CHECK-FIXES:      {{^}}  if (!p) {{{$}}
// CHECK-FIXES-NEXT: {{^}}    f("\{{$}}
// CHECK-FIXES-NEXT: {{^}}");{{$}}
// CHECK-FIXES-NEXT: {{^}}}{{$}}
// CHECK-FIXES-NEXT: {{^}}} // end of f{{$}}

#define M(x) x

int test_macros(bool b) {
  if (b) {
    return 1;
  } else
    M(return 2);
  // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: statement should be inside braces
  // CHECK-FIXES: } else {
  // CHECK-FIXES-NEXT:   M(return 2);
  // CHECK-FIXES-NEXT: }
  M(
    for (;;)
      ;
  );
  // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: statement should be inside braces
  // CHECK-FIXES: {{^}}    for (;;) {{{$}}
  // CHECK-FIXES-NEXT: {{^      ;$}}
  // CHECK-FIXES-NEXT: {{^}$}}


  #define WRAP(X) { X; }
  // This is to ensure no other CHECK-FIXES matches the macro definition:
  // CHECK-FIXES: #define WRAP(X) { X; }

  // Use-case: LLVM_DEBUG({ for(...) do_something(); });
  WRAP({
    for (;;)
      do_something("for in wrapping macro 1");
    });
  // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: statement should be inside braces
  // CHECK-FIXES: for (;;) {
  // CHECK-FIXES-NEXT: do_something("for in wrapping macro 1");
  // CHECK-FIXES-NEXT: }

  // Use-case: LLVM_DEBUG( for(...) do_something(); );
  WRAP(
    for (;;)
      do_something("for in wrapping macro 2");
    );
  // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: statement should be inside braces
  // CHECK-FIXES: for (;;) {
  // CHECK-FIXES-NEXT: do_something("for in wrapping macro 2");
  // CHECK-FIXES-NEXT: }

  // Use-case: LLVM_DEBUG( for(...) do_something() );
  // This is not supported and this test ensure it's correctly not changed.
  // We don't want to add the `}` into the Macro and there is no other way
  // to add it except for introduction of a NullStmt.
  WRAP(
    for (;;)
        do_something("for in wrapping macro 3")
    );
  // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: statement should be inside braces
  // CHECK-FIXES: WRAP(
  // CHECK-FIXES-NEXT: for (;;)
  // CHECK-FIXES-NEXT: do_something("for in wrapping macro 3")
  // CHECK-FIXES-NEXT: );

  // Taken from https://bugs.llvm.org/show_bug.cgi?id=22785
  int i;
  #define MACRO_1 i++
  #define MACRO_2
  if( i % 3) i--;
  else if( i % 2) MACRO_1;
  else MACRO_2;
  // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:18: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: statement should be inside braces
  // CHECK-FIXES: if( i % 3) { i--;
  // CHECK-FIXES-NEXT: } else if( i % 2) { MACRO_1;
  // CHECK-FIXES-NEXT: } else { MACRO_2;
  // CHECK-FIXES-NEXT: }

  // Taken from https://bugs.llvm.org/show_bug.cgi?id=22785
  #define M(x) x

  if (b)
    return 1;
  else
    return 2;
  // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: statement should be inside braces
  // CHECK-FIXES: if (b) {
  // CHECK-FIXES-NEXT: return 1;
  // CHECK-FIXES-NEXT: } else {
  // CHECK-FIXES-NEXT: return 2;
  // CHECK-FIXES-NEXT: }

  if (b)
    return 1;
  else
    M(return 2);
  // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: statement should be inside braces
  // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: statement should be inside braces
  // CHECK-FIXES: if (b) {
  // CHECK-FIXES-NEXT: return 1;
  // CHECK-FIXES-NEXT: } else {
  // CHECK-FIXES-NEXT: M(return 2);
  // CHECK-FIXES-NEXT: }

}

template <bool A>
auto constexpr_lambda_1 = [] {
  if constexpr (A) {
    1;
  }
};

template <bool A>
auto constexpr_lambda_2 = [] {
  // CHECK-MESSAGES: :[[@LINE+1]]:19: warning: statement should be inside braces
  if constexpr (A)
    1;
  // CHECK-FIXES:if constexpr (A) {
  // CHECK-FIXES-NEXT:1;
  // CHECK-FIXES-NEXT:}
};

void test_constexpr() {
  constexpr_lambda_1<false>();
  constexpr_lambda_2<false>();
}
