// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,unix.experimental.Malloc -verify -analyzer-constraints=basic %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,unix.experimental.Malloc -verify -analyzer-constraints=range %s

// These are used to trigger warnings.
typedef typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
#define NULL ((void*)0)
#define UINT_MAX -1U

//---------------
//  Plus/minus
//---------------

void separateExpressions (int a) {
  int b = a + 1;
  --b;

  char* buf = malloc(1);
  if (a != 0 && b == 0)
    return; // expected-warning{{never executed}}
  free(buf);
}

void oneLongExpression (int a) {
  // Expression canonicalization should still allow this to work, even though
  // the first term is on the left.
  int b = 15 + a + 15 - 10 - 20;

  char* buf = malloc(1);
  if (a != 0 && b == 0)
    return; // expected-warning{{never executed}}
  free(buf);
}

void mixedTypes (int a) {
  char* buf = malloc(1);

  // Different additive types should not cause crashes when constant-folding.
  // This is part of PR7406.
  int b = a + 1LL;
  if (a != 0 && (b-1) == 0) // not crash
    return; // expected-warning{{never executed}}

  int c = a + 1U;
  if (a != 0 && (c-1) == 0) // not crash
    return; // expected-warning{{never executed}}

  free(buf);
}

//---------------
//  Comparisons
//---------------

// Equality and inequality only
void eq_ne (unsigned a) {
  char* b = NULL;
  if (a == UINT_MAX)
    b = malloc(1);
  if (a+1 != 0)
    return; // no-warning
  if (a-1 != UINT_MAX-1)
    return; // no-warning
  free(b);
}

void ne_eq (unsigned a) {
  char* b = NULL;
  if (a != UINT_MAX)
    b = malloc(1);
  if (a+1 == 0)
    return; // no-warning
  if (a-1 == UINT_MAX-1)
    return; // no-warning
  free(b);
}

// Mixed typed inequalities (part of PR7406)
// These should not crash.
void mixed_eq_ne (int a) {
  char* b = NULL;
  if (a == 1)
    b = malloc(1);
  if (a+1U != 2)
    return; // no-warning
  if (a-1U != 0)
    return; // expected-warning{{never executed}}
  free(b);
}

void mixed_ne_eq (int a) {
  char* b = NULL;
  if (a != 1)
    b = malloc(1);
  if (a+1U == 2)
    return; // no-warning
  if (a-1U == 0)
    return; // expected-warning{{never executed}}
  free(b);
}


// Simple order comparisons with no adjustment
void baselineGT (unsigned a) {
  char* b = NULL;
  if (a > 0)
    b = malloc(1);
  if (a == 0)
    return; // no-warning
  free(b);
}

void baselineGE (unsigned a) {
  char* b = NULL;
  if (a >= UINT_MAX)
    b = malloc(1);
  if (a == UINT_MAX)
    free(b);
  return; // no-warning
}

void baselineLT (unsigned a) {
  char* b = NULL;
  if (a < UINT_MAX)
    b = malloc(1);
  if (a == UINT_MAX)
    return; // no-warning
  free(b);
}

void baselineLE (unsigned a) {
  char* b = NULL;
  if (a <= 0)
    b = malloc(1);
  if (a == 0)
    free(b);
  return; // no-warning
}


// Adjustment gives each of these an extra solution!
void adjustedGT (unsigned a) {
  char* b = NULL;
  if (a-1 > UINT_MAX-1)
    b = malloc(1);
  return; // expected-warning{{leak}}
}

void adjustedGE (unsigned a) {
  char* b = NULL;
  if (a-1 >= UINT_MAX-1)
    b = malloc(1);
  if (a == UINT_MAX)
    free(b);
  return; // expected-warning{{leak}}
}

void adjustedLT (unsigned a) {
  char* b = NULL;
  if (a+1 < 1)
    b = malloc(1);
  return; // expected-warning{{leak}}
}

void adjustedLE (unsigned a) {
  char* b = NULL;
  if (a+1 <= 1)
    b = malloc(1);
  if (a == 0)
    free(b);
  return; // expected-warning{{leak}}
}


// Tautologies
void tautologyGT (unsigned a) {
  char* b = malloc(1);
  if (a > UINT_MAX)
    return; // no-warning
  free(b);
}

void tautologyGE (unsigned a) {
  char* b = malloc(1);
  if (a >= 0) // expected-warning{{always true}}
    free(b);
  return; // no-warning
}

void tautologyLT (unsigned a) {
  char* b = malloc(1);
  if (a < 0) // expected-warning{{always false}}
    return; // expected-warning{{never executed}}
  free(b);
}

void tautologyLE (unsigned a) {
  char* b = malloc(1);
  if (a <= UINT_MAX)
    free(b);
  return; // no-warning
}
