// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s 
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s

void clang_analyzer_warnIfReached();
void clang_analyzer_eval(int);

struct X { X(const X&); };
void f(X x) { (void) [x]{}; }


// Lambda semantics tests.

void basicCapture() {
  int i = 5;
  [i]() mutable {
    // clang_analyzer_eval does nothing in inlined functions.
    if (i != 5)
      clang_analyzer_warnIfReached();
    ++i;
  }();
  [&i] {
    if (i != 5)
      clang_analyzer_warnIfReached();
  }();
  [&i] {
    if (i != 5)
      clang_analyzer_warnIfReached();
    i++;
  }();
  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
}

void deferredLambdaCall() {
  int i = 5;
  auto l1 = [i]() mutable {
    if (i != 5)
      clang_analyzer_warnIfReached();
    ++i;
  };
  auto l2 = [&i] {
    if (i != 5)
      clang_analyzer_warnIfReached();
  };
  auto l3 = [&i] {
    if (i != 5)
      clang_analyzer_warnIfReached();
    i++;
  };
  l1();
  l2();
  l3();
  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
}

void multipleCaptures() {
  int i = 5, j = 5;
  [i, &j]() mutable {
    if (i != 5 && j != 5)
      clang_analyzer_warnIfReached();
    ++i;
    ++j;
  }();
  clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
  clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
  [=]() mutable {
    if (i != 5 && j != 6)
      clang_analyzer_warnIfReached();
    ++i;
    ++j;
  }();
  clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
  clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
  [&]() mutable {
    if (i != 5 && j != 6)
      clang_analyzer_warnIfReached();
    ++i;
    ++j;
  }();
  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
  clang_analyzer_eval(j == 7); // expected-warning{{TRUE}}
}

void testReturnValue() {
  int i = 5;
  auto l = [i] (int a) {
    return i + a;
  };
  int b = l(3);
  clang_analyzer_eval(b == 8); // expected-warning{{TRUE}}
}

// Nested lambdas.

void testNestedLambdas() {
  int i = 5;
  auto l = [i]() mutable {
    [&i]() {
      ++i;
    }();
    if (i != 6)
      clang_analyzer_warnIfReached();
  };
  l();
  clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
}

// Captured this.

class RandomClass {
  int i;

  void captureFields() {
    i = 5;
    [this]() {
      // clang_analyzer_eval does nothing in inlined functions.
      if (i != 5)
        clang_analyzer_warnIfReached();
      ++i;
    }();
    clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
  }
};


// Nested this capture.

class RandomClass2 {
  int i;

  void captureFields() {
    i = 5;
    [this]() {
      // clang_analyzer_eval does nothing in inlined functions.
      if (i != 5)
        clang_analyzer_warnIfReached();
      ++i;
      [this]() {
        // clang_analyzer_eval does nothing in inlined functions.
        if (i != 6)
          clang_analyzer_warnIfReached();
        ++i;
      }();
    }();
    clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
  }
};


// Captured function pointers.

void inc(int &x) {
  ++x;
}

void testFunctionPointerCapture() {
  void (*func)(int &) = inc;
  int i = 5;
  [&i, func] {
    func(i);
  }();
  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
}


// Test inline defensive checks
int getNum();

void inlineDefensiveChecks() {
  int i = getNum();
  [=]() {
    if (i == 0)
      ;
  }();
  int p = 5/i;
  (void)p;
}

// CHECK: [B2 (ENTRY)]
// CHECK:   Succs (1): B1
// CHECK: [B1]
// CHECK:   1: x
// CHECK:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
// CHECK:   3: [B1.2] (CXXConstructExpr, struct X)
// CHECK:   4: [x]     {
// CHECK:    }
// CHECK:   5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
// CHECK:   Preds (1): B2
// CHECK:   Succs (1): B0
// CHECK: [B0 (EXIT)]
// CHECK:   Preds (1): B1

