// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs
// RUN: FileCheck -input-file=%t.cpp %s

#include "structures.h"

const int N = 10;

Val Arr[N];
dependent<Val> v;
dependent<Val> *pv;
Val &func(Val &);
void sideEffect(int);

void aliasing() {
  // If the loop container is only used for a declaration of a temporary
  // variable to hold each element, we can name the new variable for the
  // converted range-based loop as the temporary variable's name.

  // In the following case, "t" is used as a temporary variable to hold each
  // element, and thus we consider the name "t" aliased to the loop.
  // The extra blank braces are left as a placeholder for after the variable
  // declaration is deleted.
  for (int i = 0; i < N; ++i) {
    Val &t = Arr[i]; { }
    int y = t.x;
  }
  // CHECK: for (auto & t : Arr)
  // CHECK-NOT: Val &{{[a-z_]+}} =
  // CHECK-NEXT: { }
  // CHECK-NEXT: int y = t.x;

  // The container was not only used to initialize a temporary loop variable for
  // the container's elements, so we do not alias the new loop variable.
  for (int i = 0; i < N; ++i) {
    Val &t = Arr[i];
    int y = t.x;
    int z = Arr[i].x + t.x;
  }
  // CHECK: for (auto & elem : Arr)
  // CHECK-NEXT: Val &t = elem;
  // CHECK-NEXT: int y = t.x;
  // CHECK-NEXT: int z = elem.x + t.x;

  for (int i = 0; i < N; ++i) {
    Val t = Arr[i];
    int y = t.x;
    int z = Arr[i].x + t.x;
  }
  // CHECK: for (auto & elem : Arr)
  // CHECK-NEXT: Val t = elem;
  // CHECK-NEXT: int y = t.x;
  // CHECK-NEXT: int z = elem.x + t.x;

  // The same for pseudo-arrays like std::vector<T> (or here dependent<Val>)
  // which provide a subscript operator[].
  for (int i = 0; i < v.size(); ++i) {
    Val &t = v[i]; { }
    int y = t.x;
  }
  // CHECK: for (auto & t : v)
  // CHECK-NEXT: { }
  // CHECK-NEXT: int y = t.x;

  // The same with a call to at()
  for (int i = 0; i < pv->size(); ++i) {
    Val &t = pv->at(i); { }
    int y = t.x;
  }
  // CHECK: for (auto & t : *pv)
  // CHECK-NEXT: { }
  // CHECK-NEXT: int y = t.x;

  for (int i = 0; i < N; ++i) {
    Val &t = func(Arr[i]);
    int y = t.x;
  }
  // CHECK: for (auto & elem : Arr)
  // CHECK-NEXT: Val &t = func(elem);
  // CHECK-NEXT: int y = t.x;

  int IntArr[N];
  for (unsigned i = 0; i < N; ++i) {
    if (int alias = IntArr[i]) {
      sideEffect(alias);
    }
  }
  // CHECK: for (auto alias : IntArr)
  // CHECK-NEXT: if (alias) {

  for (unsigned i = 0; i < N; ++i) {
    while (int alias = IntArr[i]) {
      sideEffect(alias);
    }
  }
  // CHECK: for (auto alias : IntArr)
  // CHECK-NEXT: while (alias) {

  for (unsigned i = 0; i < N; ++i) {
    switch (int alias = IntArr[i]) {
    default:
      sideEffect(alias);
    }
  }
  // CHECK: for (auto alias : IntArr)
  // CHECK-NEXT: switch (alias) {

  for (unsigned i = 0; i < N; ++i) {
    for (int alias = IntArr[i]; alias < N; ++alias) {
      sideEffect(alias);
    }
  }
  // CHECK: for (auto alias : IntArr)
  // CHECK-NEXT: for (; alias < N; ++alias) {

  for (unsigned i = 0; i < N; ++i) {
    for (unsigned j = 0; int alias = IntArr[i]; ++j) {
      sideEffect(alias);
    }
  }
  // CHECK: for (auto alias : IntArr)
  // CHECK-NEXT: for (unsigned j = 0; alias; ++j) {
}

void refs_and_vals() {
  // The following tests check that the transform correctly preserves the
  // reference or value qualifiers of the aliased variable. That is, if the
  // variable was declared as a value, the loop variable will be declared as a
  // value and vice versa for references.

  S s;
  const S s_const = s;

  for (S::const_iterator it = s_const.begin(); it != s_const.end(); ++it) {
    MutableVal alias = *it; { }
    alias.x = 0;
  }
  // CHECK: for (auto alias : s_const)
  // CHECK-NOT: MutableVal {{[a-z_]+}} =
  // CHECK-NEXT: { }
  // CHECK-NEXT: alias.x = 0;

  for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
    MutableVal alias = *it; { }
    alias.x = 0;
  }
  // CHECK: for (auto alias : s)
  // CHECK-NOT: MutableVal {{[a-z_]+}} =
  // CHECK-NEXT: { }
  // CHECK-NEXT: alias.x = 0;

  for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
    MutableVal &alias = *it; { }
    alias.x = 0;
  }
  // CHECK: for (auto & alias : s)
  // CHECK-NOT: MutableVal &{{[a-z_]+}} =
  // CHECK-NEXT: { }
  // CHECK-NEXT: alias.x = 0;
}
