fix lint code reporting

Fixes: https://github.com/dart-lang/linter/issues/1568

Change-Id: I38d6138aa76fd79c11ef4d603705fdf2e29541e9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/102581
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 331d7a6..51a2b46 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -423,7 +423,7 @@
       ErrorCode errorCode,
       bool ignoreSyntheticNodes: true}) {
     if (node != null && (!node.isSynthetic || !ignoreSyntheticNodes)) {
-      reporter.reportErrorForNode(lintCode, node, arguments);
+      reporter.reportErrorForNode(errorCode ?? lintCode, node, arguments);
     }
   }
 
@@ -432,7 +432,7 @@
       ErrorCode errorCode,
       bool ignoreSyntheticTokens: true}) {
     if (token != null && (!token.isSynthetic || !ignoreSyntheticTokens)) {
-      reporter.reportErrorForToken(lintCode, token, arguments);
+      reporter.reportErrorForToken(errorCode ?? lintCode, token, arguments);
     }
   }
 
diff --git a/pkg/analyzer/test/src/lint/lint_rule_test.dart b/pkg/analyzer/test/src/lint/lint_rule_test.dart
new file mode 100644
index 0000000..55b1e3e5
--- /dev/null
+++ b/pkg/analyzer/test/src/lint/lint_rule_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2019, 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/element/element.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/error/lint_codes.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/lint/linter.dart';
+import 'package:test/test.dart';
+
+import '../../generated/test_support.dart';
+
+main() {
+  group('lint rule', () {
+    group('error code reporting', () {
+      test('reportLintForToken (custom)', () {
+        final rule = TestRule();
+        final reporter = CollectingReporter(
+            GatheringErrorListener(), new _MockSource('mock'));
+        rule.reporter = reporter;
+
+        rule.reportLintForToken(Token.eof(0),
+            errorCode: customCode, ignoreSyntheticTokens: false);
+        expect(reporter.code, customCode);
+      });
+      test('reportLintForToken (default)', () {
+        final rule = TestRule();
+        final reporter = CollectingReporter(
+            GatheringErrorListener(), new _MockSource('mock'));
+        rule.reporter = reporter;
+
+        rule.reportLintForToken(Token.eof(0), ignoreSyntheticTokens: false);
+        expect(reporter.code, rule.lintCode);
+      });
+      test('reportLint (custom)', () {
+        final rule = TestRule();
+        final reporter = CollectingReporter(
+            GatheringErrorListener(), new _MockSource('mock'));
+        rule.reporter = reporter;
+
+        final node =
+            EmptyStatementImpl(new SimpleToken(TokenType.SEMICOLON, 0));
+        rule.reportLint(node, errorCode: customCode);
+        expect(reporter.code, customCode);
+      });
+      test('reportLint (default)', () {
+        final rule = TestRule();
+        final reporter = CollectingReporter(
+            GatheringErrorListener(), new _MockSource('mock'));
+        rule.reporter = reporter;
+
+        final node =
+            EmptyStatementImpl(new SimpleToken(TokenType.SEMICOLON, 0));
+        rule.reportLint(node);
+        expect(reporter.code, rule.lintCode);
+      });
+    });
+  });
+}
+
+const LintCode customCode = const LintCode(
+    'hash_and_equals', 'Override `==` if overriding `hashCode`.',
+    correction: 'Implement `==`.');
+
+class CollectingReporter extends ErrorReporter {
+  ErrorCode code;
+
+  CollectingReporter(AnalysisErrorListener listener, Source source)
+      : super(listener, source);
+  void reportErrorForElement(ErrorCode errorCode, Element element,
+      [List<Object> arguments]) {
+    code = errorCode;
+  }
+
+  void reportErrorForNode(ErrorCode errorCode, AstNode node,
+      [List<Object> arguments]) {
+    code = errorCode;
+  }
+
+  @override
+  void reportErrorForToken(ErrorCode errorCode, Token token,
+      [List<Object> arguments]) {
+    code = errorCode;
+  }
+}
+
+class TestRule extends LintRule {
+  TestRule()
+      : super(
+          name: 'test_rule',
+          description: '',
+          details: '... tl;dr ...',
+          group: Group.errors,
+        );
+}
+
+class _MockSource implements Source {
+  @override
+  final String fullName;
+
+  _MockSource(this.fullName);
+
+  @override
+  noSuchMethod(Invocation invocation) {
+    throw new StateError('Unexpected invocation of ${invocation.memberName}');
+  }
+}
diff --git a/pkg/analyzer/test/src/lint/test_all.dart b/pkg/analyzer/test/src/lint/test_all.dart
index 47596f2..6b1afdc 100644
--- a/pkg/analyzer/test/src/lint/test_all.dart
+++ b/pkg/analyzer/test/src/lint/test_all.dart
@@ -6,6 +6,7 @@
 
 import 'config_test.dart' as config;
 import 'io_test.dart' as io;
+import 'lint_rule_test.dart' as lint_rule;
 import 'linter/test_all.dart' as linter;
 import 'project_test.dart' as project;
 import 'pub_test.dart' as pub;
@@ -14,6 +15,7 @@
   defineReflectiveSuite(() {
     config.main();
     io.main();
+    lint_rule.main();
     linter.main();
     project.main();
     pub.main();