// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: cp %t.cpp %t.base
// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs
// RUN: FileCheck -input-file=%t.cpp %s
// RUN: cp %t.base %t.cpp
// NORUN clang-modernize -count-only . %t.cpp -- -I %S/Inputs > %T/out
// NORUN FileCheck -check-prefix=COUNTONLY -input-file=%T/out %s
// RUN: diff %t.cpp %t.base

#include "structures.h"

const int N = 6;
const int NMinusOne = N - 1;
int arr[N] = {1, 2, 3, 4, 5, 6};
int (*pArr)[N] = &arr;

void f() {
  int sum = 0;
  // Update the number of correctly converted loops as this test changes:
  // COUNTONLY: 15 converted
  // COUNTONLY-NEXT: 0 potentially conflicting
  // COUNTONLY-NEXT: 0 change(s) rejected

  for (int i = 0; i < N; ++i) {
    sum += arr[i];
    int k;
  }
  // CHECK: for (auto & elem : arr) {
  // CHECK-NEXT: sum += elem;
  // CHECK-NEXT: int k;
  // CHECK-NEXT: }

  for (int i = 0; i < N; ++i) {
    printf("Fibonacci number is %d\n", arr[i]);
    sum += arr[i] + 2;
  }
  // CHECK: for (auto & elem : arr)
  // CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
  // CHECK-NEXT: sum += elem + 2;

  for (int i = 0; i < N; ++i) {
    int x = arr[i];
    int y = arr[i] + 2;
  }
  // CHECK: for (auto & elem : arr)
  // CHECK-NEXT: int x = elem;
  // CHECK-NEXT: int y = elem + 2;

  for (int i = 0; i < N; ++i) {
    int x = N;
    x = arr[i];
  }
  // CHECK: for (auto & elem : arr)
  // CHECK-NEXT: int x = N;
  // CHECK-NEXT: x = elem;

  for (int i = 0; i < N; ++i) {
    arr[i] += 1;
  }
  // CHECK: for (auto & elem : arr) {
  // CHECK-NEXT: elem += 1;
  // CHECK-NEXT: }

  for (int i = 0; i < N; ++i) {
    int x = arr[i] + 2;
    arr[i] ++;
  }
  // CHECK: for (auto & elem : arr)
  // CHECK-NEXT: int x = elem + 2;
  // CHECK-NEXT: elem ++;

  for (int i = 0; i < N; ++i) {
    arr[i] = 4 + arr[i];
  }
  // CHECK: for (auto & elem : arr)
  // CHECK-NEXT: elem = 4 + elem;

  for (int i = 0; i < NMinusOne + 1; ++i) {
    sum += arr[i];
  }
  // CHECK: for (auto & elem : arr) {
  // CHECK-NEXT: sum += elem;
  // CHECK-NEXT: }

  for (int i = 0; i < N; ++i) {
    printf("Fibonacci number %d has address %p\n", arr[i], &arr[i]);
    sum += arr[i] + 2;
  }
  // CHECK: for (auto & elem : arr)
  // CHECK-NEXT: printf("Fibonacci number %d has address %p\n", elem, &elem);
  // CHECK-NEXT: sum += elem + 2;

  Val teas[N];
  for (int i = 0; i < N; ++i) {
    teas[i].g();
  }
  // CHECK: for (auto & tea : teas) {
  // CHECK-NEXT: tea.g();
  // CHECK-NEXT: }
}

struct HasArr {
  int Arr[N];
  Val ValArr[N];
  void implicitThis() {
    for (int i = 0; i < N; ++i) {
      printf("%d", Arr[i]);
    }
    // CHECK: for (auto & elem : Arr) {
    // CHECK-NEXT: printf("%d", elem);
    // CHECK-NEXT: }

    for (int i = 0; i < N; ++i) {
      printf("%d", ValArr[i].x);
    }
    // CHECK: for (auto & elem : ValArr) {
    // CHECK-NEXT: printf("%d", elem.x);
    // CHECK-NEXT: }
  }

  void explicitThis() {
    for (int i = 0; i < N; ++i) {
      printf("%d", this->Arr[i]);
    }
    // CHECK: for (auto & elem : this->Arr) {
    // CHECK-NEXT: printf("%d", elem);
    // CHECK-NEXT: }

    for (int i = 0; i < N; ++i) {
      printf("%d", this->ValArr[i].x);
    }
    // CHECK: for (auto & elem : this->ValArr) {
    // CHECK-NEXT: printf("%d", elem.x);
    // CHECK-NEXT: }
  }
};

// Loops whose bounds are value-dependent shold not be converted.
template<int N>
void dependentExprBound() {
  for (int i = 0; i < N; ++i)
    arr[i] = 0;
  // CHECK: for (int i = 0; i < N; ++i)
  // CHECK-NEXT: arr[i] = 0;
}
template void dependentExprBound<20>();

void memberFunctionPointer() {
  Val v;
  void (Val::*mfpArr[N])(void) = { &Val::g };
  for (int i = 0; i < N; ++i)
    (v.*mfpArr[i])();
  // CHECK: for (auto & elem : mfpArr)
  // CHECK-NEXT: (v.*elem)();
}
