text: // RUN: %clang_analyze_cc1 %s \
  // RUN:   -verify=expected,tracking \
  // RUN:   -analyzer-config track-conditions=true \
  // RUN:   -analyzer-output=text \
  // RUN:   -analyzer-checker=core
  
  // RUN: not %clang_analyze_cc1 -verify %s \
  // RUN:   -analyzer-checker=core \
  // RUN:   -analyzer-config track-conditions-debug=true \
  // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-DEBUG
  
  // CHECK-INVALID-DEBUG: (frontend): invalid input for analyzer-config option
  // CHECK-INVALID-DEBUG-SAME:        'track-conditions-debug', that expects
  // CHECK-INVALID-DEBUG-SAME:        'track-conditions' to also be enabled
  //
  // RUN: %clang_analyze_cc1 %s \
  // RUN:   -verify=expected,tracking,debug \
  // RUN:   -analyzer-config track-conditions=true \
  // RUN:   -analyzer-config track-conditions-debug=true \
  // RUN:   -analyzer-output=text \
  // RUN:   -analyzer-checker=core
  
  // RUN: %clang_analyze_cc1 %s -verify \
  // RUN:   -analyzer-output=text \
  // RUN:   -analyzer-checker=core
  
  namespace example_1 {
  int flag;
  bool coin();
  
  void foo() {
    flag = coin(); // tracking-note{{Value assigned to 'flag'}}
  }
  
  void test() {
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
    flag = 1;
  
    foo(); // TODO: Add nodes here about flag's value being invalidated.
    if (flag) // expected-note   {{Assuming 'flag' is 0}}
              // expected-note@-1{{Taking false branch}}
      x = new int;
  
    foo(); // tracking-note{{Calling 'foo'}}
           // tracking-note@-1{{Returning from 'foo'}}
  
    if (flag) // expected-note   {{Assuming 'flag' is not equal to 0}}
              // expected-note@-1{{Taking true branch}}
              // debug-note@-2{{Tracking condition 'flag'}}
  
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace example_1
  
  namespace example_2 {
  int flag;
  bool coin();
  
  void foo() {
    flag = coin(); // tracking-note{{Value assigned to 'flag'}}
  }
  
  void test() {
    int *x = 0;
    flag = 1;
  
    foo();
    if (flag) // expected-note   {{Assuming 'flag' is 0}}
              // expected-note@-1{{Taking false branch}}
      x = new int;
  
    x = 0; // expected-note{{Null pointer value stored to 'x'}}
  
    foo(); // tracking-note{{Calling 'foo'}}
           // tracking-note@-1{{Returning from 'foo'}}
  
    if (flag) // expected-note   {{Assuming 'flag' is not equal to 0}}
              // expected-note@-1{{Taking true branch}}
              // debug-note@-2{{Tracking condition 'flag'}}
  
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace example_2
  
  namespace global_variable_invalidation {
  int flag;
  bool coin();
  
  void foo() {
    // coin() could write bar, do it's invalidated.
    flag = coin(); // tracking-note{{Value assigned to 'flag'}}
                   // tracking-note@-1{{Value assigned to 'bar'}}
  }
  
  int bar;
  
  void test() {
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
    flag = 1;
  
    foo(); // tracking-note{{Calling 'foo'}}
           // tracking-note@-1{{Returning from 'foo'}}
  
    if (bar) // expected-note   {{Assuming 'bar' is not equal to 0}}
             // expected-note@-1{{Taking true branch}}
             // debug-note@-2{{Tracking condition 'bar'}}
      if (flag) // expected-note   {{Assuming 'flag' is not equal to 0}}
                // expected-note@-1{{Taking true branch}}
                // debug-note@-2{{Tracking condition 'flag'}}
  
        *x = 5; // expected-warning{{Dereference of null pointer}}
                // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace global_variable_invalidation
  
  namespace variable_declaration_in_condition {
  bool coin();
  
  bool foo() {
    return coin(); // tracking-note{{Returning value}}
  }
  
  int bar;
  
  void test() {
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
  
    if (int flag = foo()) // tracking-note{{Calling 'foo'}}
                          // tracking-note@-1{{Returning from 'foo'}}
                          // tracking-note@-2{{'flag' initialized here}}
                          // debug-note@-3{{Tracking condition 'flag'}}
                          // expected-note@-4{{Assuming 'flag' is not equal to 0}}
                          // expected-note@-5{{Taking true branch}}
  
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace variable_declaration_in_condition
  
  namespace conversion_to_bool {
  bool coin();
  
  struct ConvertsToBool {
    operator bool() const { return coin(); } // tracking-note{{Returning value}}
  };
  
  void test() {
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
  
    if (ConvertsToBool())
      // tracking-note@-1 {{Calling 'ConvertsToBool::operator bool'}}
      // tracking-note@-2{{Returning from 'ConvertsToBool::operator bool'}}
      // debug-note@-3{{Tracking condition 'ConvertsToBool()'}}
      // expected-note@-4{{Assuming the condition is true}}
      // expected-note@-5{{Taking true branch}}
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  
  } // end of namespace variable_declaration_in_condition
  
  namespace unimportant_returning_value_note {
  bool coin();
  
  bool flipCoin() { return coin(); } // tracking-note{{Returning value}}
  
  void i(int *ptr) {
    if (ptr) // expected-note{{Assuming 'ptr' is null}}
             // expected-note@-1{{Taking false branch}}
      ;
    if (!flipCoin())
      // tracking-note@-1{{Calling 'flipCoin'}}
      // tracking-note@-2{{Returning from 'flipCoin'}}
      // debug-note@-3{{Tracking condition '!flipCoin()'}}
      // expected-note@-4{{Assuming the condition is true}}
      // expected-note@-5{{Taking true branch}}
      *ptr = 5; // expected-warning{{Dereference of null pointer}}
                // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace unimportant_returning_value_note
  
  namespace important_returning_value_note {
  bool coin();
  
  bool flipCoin() {
    if (coin()) // tracking-note{{Assuming the condition is false}}
                // tracking-note@-1{{Taking false branch}}
                // debug-note@-2{{Tracking condition 'coin()'}}
      return true;
    return coin(); // tracking-note{{Returning value}}
  }
  
  void i(int *ptr) {
    if (ptr) // expected-note{{Assuming 'ptr' is null}}
             // expected-note@-1{{Taking false branch}}
      ;
    if (!flipCoin())
      // tracking-note@-1{{Calling 'flipCoin'}}
      // tracking-note@-2{{Returning from 'flipCoin'}}
      // debug-note@-3{{Tracking condition '!flipCoin()'}}
      // expected-note@-4{{Assuming the condition is true}}
      // expected-note@-5{{Taking true branch}}
      *ptr = 5; // expected-warning{{Dereference of null pointer}}
                // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace important_returning_value_note
  
  namespace tracked_condition_is_only_initialized {
  int getInt();
  
  void f() {
    int flag = getInt(); // tracking-note{{'flag' initialized here}}
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
    if (flag) // expected-note{{Assuming 'flag' is not equal to 0}}
              // expected-note@-1{{Taking true branch}}
              // debug-note@-2{{Tracking condition 'flag'}}
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace tracked_condition_is_only_initialized
  
  namespace tracked_condition_written_in_same_stackframe {
  int flag;
  int getInt();
  
  void f(int y) {
    y = 1; // tracking-note{{The value 1 is assigned to 'y'}}
    flag = y; // tracking-note{{The value 1 is assigned to 'flag'}}
  
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
    if (flag) // expected-note{{'flag' is 1}}
              // expected-note@-1{{Taking true branch}}
              // debug-note@-2{{Tracking condition 'flag'}}
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace tracked_condition_written_in_same_stackframe
  
  namespace tracked_condition_written_in_nested_stackframe {
  int flag;
  int getInt();
  
  void foo() {
    int y;
    y = 1; // tracking-note{{The value 1 is assigned to 'y'}}
    flag = y; // tracking-note{{The value 1 is assigned to 'flag'}}
  
  }
  
  void f(int y) {
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
  
    foo(); // tracking-note{{Calling 'foo'}}
           // tracking-note@-1{{Returning from 'foo'}}
  
    if (flag) // expected-note{{'flag' is 1}}
              // expected-note@-1{{Taking true branch}}
              // debug-note@-2{{Tracking condition 'flag'}}
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  } // end of namespace tracked_condition_written_in_nested_stackframe
  
  namespace collapse_point_not_in_condition {
  
  [[noreturn]] void halt();
  
  void assert(int b) {
    if (!b) // tracking-note{{Assuming 'b' is not equal to 0}}
            // tracking-note@-1{{Taking false branch}}
      halt();
  }
  
  void f(int flag) {
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
  
    assert(flag); // tracking-note{{Calling 'assert'}}
                  // tracking-note@-1{{Returning from 'assert'}}
  
    if (flag) // expected-note{{'flag' is not equal to 0}}
              // expected-note@-1{{Taking true branch}}
              // debug-note@-2{{Tracking condition 'flag'}}
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  
  } // end of namespace collapse_point_not_in_condition
  
  namespace unimportant_write_before_collapse_point {
  
  [[noreturn]] void halt();
  
  void assert(int b) {
    if (!b) // tracking-note{{Assuming 'b' is not equal to 0}}
            // tracking-note@-1{{Taking false branch}}
      halt();
  }
  int getInt();
  
  void f(int flag) {
    int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
  
    flag = getInt(); // tracking-note{{Value assigned to 'flag'}}
    assert(flag); // tracking-note{{Calling 'assert'}}
                  // tracking-note@-1{{Returning from 'assert'}}
  
    if (flag) // expected-note{{'flag' is not equal to 0}}
              // expected-note@-1{{Taking true branch}}
              // debug-note@-2{{Tracking condition 'flag'}}
      *x = 5; // expected-warning{{Dereference of null pointer}}
              // expected-note@-1{{Dereference of null pointer}}
  }
  
  } // end of namespace unimportant_write_before_collapse_point
  