// 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"

// Single FileCheck line to make sure that no loops are converted.
// CHECK-NOT: for ({{.*[^:]:[^:].*}})

S s;
T t;
U u;

struct BadBeginEnd : T {
  iterator notBegin();
  iterator notEnd();
};

void notBeginOrEnd() {
  BadBeginEnd Bad;
  for (T::iterator i = Bad.notBegin(), e = Bad.end(); i != e; ++i)
    int k = *i;

  for (T::iterator i = Bad.begin(), e = Bad.notEnd(); i != e; ++i)
    int k = *i;
}

void badLoopShapes() {
  for (T::iterator i = t.begin(), e = t.end(), f = e; i != e; ++i)
    int k = *i;

  for (T::iterator i = t.begin(), e = t.end(); i != e; )
    int k = *i;

  for (T::iterator i = t.begin(), e = t.end(); ; ++i)
    int k = *i;

  T::iterator outsideI;
  T::iterator outsideE;

  for (; outsideI != outsideE ; ++outsideI)
    int k = *outsideI;
}

void iteratorArrayMix() {
  int lower;
  const int N = 6;
  for (T::iterator i = t.begin(), e = t.end(); lower < N; ++i)
    int k = *i;

  for (T::iterator i = t.begin(), e = t.end(); lower < N; ++lower)
    int k = *i;
}

struct ExtraConstructor : T::iterator {
  ExtraConstructor(T::iterator, int);
  explicit ExtraConstructor(T::iterator);
};

void badConstructor() {
  for (T::iterator i = ExtraConstructor(t.begin(), 0), e = t.end();
       i != e; ++i)
    int k = *i;
  for (T::iterator i = ExtraConstructor(t.begin()), e = t.end(); i != e; ++i)
    int k = *i;
}

void iteratorMemberUsed() {
  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
    i.x = *i;

  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
    int k = i.x + *i;

  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
    int k = e.x + *i;
}

void iteratorMethodCalled() {
  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
    i.insert(3);

  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
    if (i != i)
      int k = 3;
}

void iteratorOperatorCalled() {
  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
    int k = *(++i);

  for (S::iterator i = s.begin(), e = s.end(); i != e; ++i)
    MutableVal k = *(++i);
}

void differentContainers() {
  T other;
  for (T::iterator i = t.begin(), e = other.end(); i != e; ++i)
    int k = *i;

  for (T::iterator i = other.begin(), e = t.end(); i != e; ++i)
    int k = *i;

  S otherS;
  for (S::iterator i = s.begin(), e = otherS.end(); i != e; ++i)
    MutableVal k = *i;

  for (S::iterator i = otherS.begin(), e = s.end(); i != e; ++i)
    MutableVal k = *i;
}

void wrongIterators() {
  T::iterator other;
  for (T::iterator i = t.begin(), e = t.end(); i != other; ++i)
    int k = *i;
}

struct EvilArrow : U {
  // Please, no one ever write code like this.
  U* operator->();
};

void differentMemberAccessTypes() {
  EvilArrow A;
  for (EvilArrow::iterator i = A.begin(), e = A->end(); i != e; ++i)
    Val k = *i;
  for (EvilArrow::iterator i = A->begin(), e = A.end(); i != e; ++i)
    Val k = *i;
}

void f(const T::iterator &it, int);
void f(const T &it, int);
void g(T &it, int);

void iteratorPassedToFunction() {
  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
    f(i, *i);
}

// FIXME: Disallow this except for containers passed by value and/or const
// reference. Or maybe this is correct enough for any container?
void containerPassedToFunction() {
//  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
//    f(t, *i);
//  for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
//    g(t, *i);
}

// FIXME: These tests can be removed if this tool ever does enough analysis to
// decide that this is a safe transformation.
// Until then, we don't want it applied.
void iteratorDefinedOutside() {
  T::iterator theEnd = t.end();
  for (T::iterator i = t.begin(); i != theEnd; ++i)
    int k = *i;

  T::iterator theBegin = t.begin();
  for (T::iterator e = t.end(); theBegin != e; ++theBegin)
    int k = *theBegin;
}
