//RUN: %clang_analyze_cc1 -cc1 -std=c++11  -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection %s -verify
//RUN: %clang_analyze_cc1 -cc1 -std=c++11  -analyzer-checker=core,apiModeling.google.GTest,debug.ExprInspection -DGTEST_VERSION_1_8_AND_LATER=1 %s -verify

void clang_analyzer_eval(int);
void clang_analyzer_warnIfReached();

namespace std {
  class string {
    public:
    ~string();
    const char *c_str();
  };
}

namespace testing {

class Message { };
class TestPartResult {
 public:
  enum Type {
    kSuccess,
    kNonFatalFailure,
    kFatalFailure
  };
};

namespace internal {

class AssertHelper {
 public:
  AssertHelper(TestPartResult::Type type, const char* file, int line,
               const char* message);
  ~AssertHelper();
  void operator=(const Message& message) const;
};


template <typename T>
struct AddReference { typedef T& type; };
template <typename T>
struct AddReference<T&> { typedef T& type; };
template <typename From, typename To>
class ImplicitlyConvertible {
 private:
  static typename AddReference<From>::type MakeFrom();
  static char Helper(To);
  static char (&Helper(...))[2];
 public:
  static const bool value =
      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
};
template <typename From, typename To>
const bool ImplicitlyConvertible<From, To>::value;
template<bool> struct EnableIf;
template<> struct EnableIf<true> { typedef void type; };

} // end internal


class AssertionResult {
public:

  // The implementation for the copy constructor is not exposed in the
  // interface.
  AssertionResult(const AssertionResult& other);

#if defined(GTEST_VERSION_1_8_AND_LATER)
  template <typename T>
  explicit AssertionResult(
      const T& success,
      typename internal::EnableIf<
          !internal::ImplicitlyConvertible<T, AssertionResult>::value>::type*
          /*enabler*/ = 0)
      : success_(success) {}
#else
  explicit AssertionResult(bool success) : success_(success) {}
#endif

  operator bool() const { return success_; }

  // The actual AssertionResult does not have an explicit destructor, but
  // it does have a non-trivial member veriable, so we add a destructor here
  // to force temporary cleanups.
  ~AssertionResult();
private:

  bool success_;
};

namespace internal {
std::string GetBoolAssertionFailureMessage(
    const AssertionResult& assertion_result,
    const char* expression_text,
    const char* actual_predicate_value,
    const char* expected_predicate_value);
} // end internal

} // end testing

#define GTEST_MESSAGE_AT_(file, line, message, result_type) \
  ::testing::internal::AssertHelper(result_type, file, line, message) \
    = ::testing::Message()

#define GTEST_MESSAGE_(message, result_type) \
  GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type)

#define GTEST_FATAL_FAILURE_(message) \
  return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)

#define GTEST_NONFATAL_FAILURE_(message) \
  GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)

# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default:

#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (const ::testing::AssertionResult gtest_ar_ = \
      ::testing::AssertionResult(expression)) \
    ; \
  else \
    fail(::testing::internal::GetBoolAssertionFailureMessage(\
        gtest_ar_, text, #actual, #expected).c_str())

#define EXPECT_TRUE(condition) \
  GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
                      GTEST_NONFATAL_FAILURE_)
#define ASSERT_TRUE(condition) \
  GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
                      GTEST_FATAL_FAILURE_)

#define ASSERT_FALSE(condition) \
  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
                      GTEST_FATAL_FAILURE_)

void testAssertTrue(int *p) {
  ASSERT_TRUE(p != nullptr);
  EXPECT_TRUE(1 == *p); // no-warning
}

void testAssertFalse(int *p) {
  ASSERT_FALSE(p == nullptr);
  EXPECT_TRUE(1 == *p); // no-warning
}

void testConstrainState(int p) {
  ASSERT_TRUE(p == 7);

  clang_analyzer_eval(p == 7); // expected-warning {{TRUE}}

  ASSERT_TRUE(false);
  clang_analyzer_warnIfReached(); // no-warning
}

void testAssertSymbolicPtr(const bool *b) {
  ASSERT_TRUE(*b); // no-crash

  clang_analyzer_eval(*b); // expected-warning{{TRUE}}
}

void testAssertSymbolicRef(const bool &b) {
  ASSERT_TRUE(b); // no-crash

  clang_analyzer_eval(b); // expected-warning{{TRUE}}
}
