[Lint] Prefer intValue.isEven check (#2076)

diff --git a/example/all.yaml b/example/all.yaml
index 8598d91..92a35c6 100644
--- a/example/all.yaml
+++ b/example/all.yaml
@@ -160,6 +160,7 @@
     - unsafe_html
     - use_full_hex_values_for_flutter_colors
     - use_function_type_syntax_for_parameters
+    - use_is_even_rather_than_modulo
     - use_key_in_widget_constructors
     - use_raw_strings
     - use_rethrow_when_possible
diff --git a/lib/src/rules.dart b/lib/src/rules.dart
index 5bc3f38..502e537 100644
--- a/lib/src/rules.dart
+++ b/lib/src/rules.dart
@@ -115,6 +115,7 @@
 import 'rules/prefer_initializing_formals.dart';
 import 'rules/prefer_inlined_adds.dart';
 import 'rules/prefer_int_literals.dart';
+import 'rules/use_is_even_rather_than_modulo.dart';
 import 'rules/prefer_interpolation_to_compose_strings.dart';
 import 'rules/prefer_is_empty.dart';
 import 'rules/prefer_is_not_empty.dart';
@@ -337,6 +338,7 @@
     ..register(UnsafeHtml())
     ..register(UseFullHexValuesForFlutterColors())
     ..register(UseFunctionTypeSyntaxForParameters())
+    ..register(UseIsEvenRatherThanModuloCheck())
     ..register(UseKeyInWidgetConstructors())
     ..register(UseRethrowWhenPossible())
     ..register(UseRawStrings())
diff --git a/lib/src/rules/use_is_even_rather_than_modulo.dart b/lib/src/rules/use_is_even_rather_than_modulo.dart
new file mode 100644
index 0000000..cfbb248
--- /dev/null
+++ b/lib/src/rules/use_is_even_rather_than_modulo.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+
+import '../analyzer.dart';
+
+const _desc =
+    r'Prefer intValue.isOdd/isEven instead of checking the result of % 2.';
+
+const _details = r'''
+
+**PREFER** the use of intValue.isOdd/isEven to check for evenness.
+
+**BAD:**
+```
+bool isEven = 1 % 2 == 0;
+bool isOdd = 13 % 2 == 1;
+```
+
+**GOOD:**
+```
+bool isEven = 1.isEven;
+bool isOdd = 13.isOdd;
+```
+
+''';
+
+class UseIsEvenRatherThanModuloCheck extends LintRule implements NodeLintRule {
+  UseIsEvenRatherThanModuloCheck()
+      : super(
+            name: 'use_is_even_rather_than_modulo',
+            description: _desc,
+            details: _details,
+            group: Group.style);
+
+  @override
+  void registerNodeProcessors(NodeLintRegistry registry,
+      [LinterContext context]) {
+    final visitor = _Visitor(this);
+    registry.addBinaryExpression(this, visitor);
+  }
+}
+
+class _Visitor extends SimpleAstVisitor<void> {
+  final LintRule rule;
+  _Visitor(this.rule);
+
+  @override
+  void visitBinaryExpression(BinaryExpression node) {
+    // This lint error only happens when the operator is equality.
+    if (node.operator.type != TokenType.EQ_EQ) {
+      return;
+    }
+    var left = node.leftOperand;
+    var leftType = left.staticType;
+    var right = node.rightOperand;
+    var rightType = right.staticType;
+    // Both sides have to have static type of int
+    if (!(right is IntegerLiteral &&
+        leftType.isDartCoreInt == true &&
+        rightType.isDartCoreInt == true)) {
+      return;
+    }
+    // The left side expression has to be modulo by 2 type.
+    if (left is BinaryExpression) {
+      var rightChild = left.rightOperand;
+      var rightChildType = rightChild.staticType;
+      if (left.operator.type == TokenType.PERCENT &&
+          rightChild is IntegerLiteral &&
+          rightChild.value == 2 &&
+          rightChildType.isDartCoreInt == true) {
+        rule.reportLint(node);
+      }
+    }
+  }
+}
diff --git a/test/rules/use_is_even_rather_than_modulo.dart b/test/rules/use_is_even_rather_than_modulo.dart
new file mode 100644
index 0000000..d8d8ac7
--- /dev/null
+++ b/test/rules/use_is_even_rather_than_modulo.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// test w/ `pub run test -N use_is_even_rather_than_modulo`
+
+bool isEven = 1 % 2 == 0; //LINT
+bool isOdd = 13 % 2 == 1; //LINT
+int number = 3;
+bool c = number % 2 == 0; //LINT
+
+// Not equality operator is okay
+bool a = 1 % 2 >= 0;
+bool d = number % 2 != 0;
+
+// Modulo by any other number than 2 is okay
+d = number % 3 == 1;
+
+// Not modulo operation is okay.
+d = number + 2 == 0;
+
+// Compare to not an IntegerLiteral is okay.
+bool b = 1 % 2 == 3-3;
+// Unknown operand type is okay.
+Class tmp;
+a = tmp % 2 == 0;
+
+a = 1.isEven;
+a = 2.isOdd;