Support for 'null =' and 'null !=' for nullability.

R=brianwilkerson@google.com, paulberry@google.com

Change-Id: I84b186db9888ebc14abbc12acbba7fe4d5809072
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107191
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index bc05fe3..d2a5827 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -270,7 +270,6 @@
     } else if (operator == TokenType.BANG_EQ) {
       left.accept(this);
       right.accept(this);
-      // TODO(scheglov) Support `null != name`
       if (right is NullLiteral) {
         if (left is SimpleIdentifier) {
           var element = left.staticElement;
@@ -278,9 +277,15 @@
             flow.conditionNotEqNull(node, element);
           }
         }
+      } else if (left is NullLiteral) {
+        if (right is SimpleIdentifier) {
+          var element = right.staticElement;
+          if (element is VariableElement) {
+            flow.conditionNotEqNull(node, element);
+          }
+        }
       }
     } else if (operator == TokenType.EQ_EQ) {
-      // TODO(scheglov) Support `null == name`
       left.accept(this);
       right.accept(this);
       if (right is NullLiteral) {
@@ -290,6 +295,13 @@
             flow.conditionEqNull(node, element);
           }
         }
+      } else if (left is NullLiteral) {
+        if (right is SimpleIdentifier) {
+          var element = right.staticElement;
+          if (element is VariableElement) {
+            flow.conditionEqNull(node, element);
+          }
+        }
       }
     } else if (operator == TokenType.QUESTION_QUESTION) {
       left.accept(this);
diff --git a/pkg/analyzer/test/src/dart/resolution/flow_analysis_test.dart b/pkg/analyzer/test/src/dart/resolution/flow_analysis_test.dart
index 89142a2..77ad390 100644
--- a/pkg/analyzer/test/src/dart/resolution/flow_analysis_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/flow_analysis_test.dart
@@ -1431,7 +1431,18 @@
     assertNonNullable('b; // 2', 'a; // 3', 'b; // 4', 'b; // 6');
   }
 
-  test_if_notNull_thenExit() async {
+  test_if_notNull_thenExit_left() async {
+    await trackCode(r'''
+void f(int x) {
+  if (null != x) return;
+  x; // 1
+}
+''');
+    assertNullable('x; // 1');
+    assertNonNullable();
+  }
+
+  test_if_notNull_thenExit_right() async {
     await trackCode(r'''
 void f(int x) {
   if (x != null) return;
@@ -1442,7 +1453,18 @@
     assertNonNullable();
   }
 
-  test_if_null_thenExit() async {
+  test_if_null_thenExit_left() async {
+    await trackCode(r'''
+void f(int x) {
+  if (null == x) return;
+  x; // 1
+}
+''');
+    assertNullable();
+    assertNonNullable('x; // 1');
+  }
+
+  test_if_null_thenExit_right() async {
     await trackCode(r'''
 void f(int x) {
   if (x == null) return;