linter: require LintRules to either declare 'lintCode' or 'lintCodes'

Work towards https://github.com/dart-lang/sdk/issues/50986

This found a few lint rules that had not declared a `lintCode` or
`lintCodes`! So I corrent them as well, and a few grammar nits in their
descriptions.

Cq-Include-Trybots: luci.dart.try:flutter-analyze-try,analyzer-win-release-try,pkg-win-release-try
Change-Id: I2bca3bbc382d1f25a3291326eb3b660c06d8917d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/372183
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Sam Rawlins 2024-07-05 04:53:18 +00:00 committed by Commit Queue
parent a5c6c3374f
commit f274b8a4c4
18 changed files with 142 additions and 23 deletions

View file

@ -4,6 +4,7 @@
import 'package:analysis_server/lsp_protocol/protocol.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analyzer/src/dart/error/lint_codes.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/registry.dart';
import 'package:analyzer/src/test_utilities/test_code_format.dart';
@ -24,6 +25,12 @@ void main() {
/// A version of `camel_case_types` that is deprecated.
class DeprecatedCamelCaseTypes extends LintRule {
static const LintCode code = LintCode('camel_case_types',
"The type name '{0}' isn't an UpperCamelCase identifier.",
correctionMessage:
'Try changing the name to follow the UpperCamelCase style.',
hasPublishedDocs: true);
DeprecatedCamelCaseTypes()
: super(
name: 'camel_case_types',
@ -32,6 +39,9 @@ class DeprecatedCamelCaseTypes extends LintRule {
description: '',
details: '',
);
@override
LintCode get lintCode => code;
}
@reflectiveTest

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/completion/yaml/analysis_options_generator.dart';
import 'package:analyzer/src/dart/error/lint_codes.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/registry.dart';
import 'package:analyzer/src/task/options.dart';
@ -154,7 +155,7 @@ linter:
}
void test_linter_rules_internal() {
registerRule(InternalLint());
registerRule(InternalRule());
getCompletions('''
linter:
@ -255,8 +256,11 @@ li^
}
}
class InternalLint extends LintRule {
InternalLint()
class InternalRule extends LintRule {
static const LintCode code = LintCode('internal_rule', 'Internal rule.',
correctionMessage: 'Try internal rule.');
InternalRule()
: super(
name: 'internal_lint',
categories: {Category.style},
@ -264,4 +268,7 @@ class InternalLint extends LintRule {
description: '',
details: '',
);
@override
LintCode get lintCode => code;
}

View file

@ -2,6 +2,7 @@
// 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/src/dart/error/lint_codes.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/registry.dart';
import 'package:linter/src/rules.dart';
@ -16,6 +17,9 @@ void main() {
}
class DeprecatedRule extends LintRule {
static const LintCode code = LintCode('deprecated_rule', 'Deprecated rule.',
correctionMessage: 'Try deprecated rule.');
DeprecatedRule()
: super(
name: 'deprecated_rule',
@ -24,9 +28,15 @@ class DeprecatedRule extends LintRule {
categories: {Category.errors},
state: State.deprecated(since: dart2_12),
);
@override
LintCode get lintCode => code;
}
class RemovedRule extends LintRule {
static const LintCode code = LintCode('removed_rule', 'Removed rule.',
correctionMessage: 'Try removed rule.');
RemovedRule()
: super(
name: 'removed_rule',
@ -34,6 +44,9 @@ class RemovedRule extends LintRule {
details: '...',
categories: {Category.errors},
state: State.removed());
@override
LintCode get lintCode => code;
}
@reflectiveTest

View file

@ -258,8 +258,15 @@ abstract class LintRule {
/// A list of incompatible rule ids.
List<String> get incompatibleRules => const [];
/// The lint code associated with this linter.
LintCode get lintCode => _LintCode(name, description);
/// The lint code associated with this linter, if it is only associated with a
/// single lint code.
///
/// Note that this property is just a convenient shorthand for a rule to
/// associate a lint rule with a single lint code. Use [lintCodes] for the
/// full list of (possibly multiple) lint codes which a lint rule may be
/// associated with.
LintCode get lintCode => throw UnimplementedError(
"'lintCode' is not implemented for $runtimeType");
/// The lint codes associated with this lint rule.
List<LintCode> get lintCodes => [lintCode];
@ -402,16 +409,6 @@ class _ConstantAnalysisErrorListener extends AnalysisErrorListener {
}
}
class _LintCode extends LintCode {
static final registry = <String, _LintCode>{};
factory _LintCode(String name, String message) {
return registry[name + message] ??= _LintCode._(name, message);
}
_LintCode._(super.name, super.message);
}
extension on AstNode {
/// Whether [ConstantVerifier] reports an error when computing the value of
/// `this` as a constant.

View file

@ -72,6 +72,9 @@ int a = 0;
}
class _AvoidIntRule extends LintRule {
static const LintCode code = LintCode('avoid_int', 'Avoid int.',
correctionMessage: 'Try avoiding int.');
_AvoidIntRule()
: super(
name: 'avoid_int',
@ -80,6 +83,9 @@ class _AvoidIntRule extends LintRule {
categories: {Category.errors},
);
@override
LintCode get lintCode => code;
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {

View file

@ -150,6 +150,9 @@ class CollectingReporter extends ErrorReporter {
}
class TestRule extends LintRule {
static const LintCode code =
LintCode('test_rule', 'Test rule.', correctionMessage: 'Try test rule.');
TestRule()
: super(
name: 'test_rule',
@ -157,6 +160,9 @@ class TestRule extends LintRule {
details: '... tl;dr ...',
categories: {Category.errors},
);
@override
LintCode get lintCode => code;
}
class _MockSource implements Source {

View file

@ -370,6 +370,10 @@ linter:
}
class TestRule extends LintRule {
static const LintCode code = LintCode(
'fantastic_test_rule', 'Fantastic test rule.',
correctionMessage: 'Try fantastic test rule.');
TestRule()
: super(
name: 'fantastic_test_rule',
@ -385,4 +389,7 @@ class TestRule extends LintRule {
details: '',
categories: {Category.style},
);
@override
LintCode get lintCode => code;
}

View file

@ -570,6 +570,10 @@ analyzer:
}
class TestRule extends LintRule {
static const LintCode code = LintCode(
'fantastic_test_rule', 'Fantastic test rule.',
correctionMessage: 'Try fantastic test rule.');
TestRule()
: super(
name: 'fantastic_test_rule',
@ -585,4 +589,7 @@ class TestRule extends LintRule {
details: '',
categories: {Category.style},
);
@override
LintCode get lintCode => code;
}

View file

@ -27259,7 +27259,9 @@ import 'bar.dart';
### prefer_typing_uninitialized_variables
_Prefer typing uninitialized variables and fields._
_An uninitialized field should have an explicit type annotation._
_An uninitialized variable should have an explicit type annotation._
#### Description
@ -28593,7 +28595,9 @@ part of 'lib.dart';
### use_super_parameters
_Use super-initializer parameters where possible._
_Convert '{0}' to a super parameter._
_Convert {0} to super parameters._
#### Description

View file

@ -12,6 +12,12 @@ This rule has been removed.
''';
class AvoidUnstableFinalFields extends LintRule {
static const LintCode code = LintCode(
'avoid_unstable_final_fields',
'Avoid overriding a final field to return '
'different values if called multiple times.',
hasPublishedDocs: true);
AvoidUnstableFinalFields()
: super(
name: 'avoid_unstable_final_fields',
@ -20,6 +26,9 @@ class AvoidUnstableFinalFields extends LintRule {
categories: {Category.errors},
state: State.removed());
@override
LintCode get lintCode => code;
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {}

View file

@ -178,6 +178,14 @@ class DirectivesOrdering extends LintRule {
details: _details,
categories: {Category.style});
@override
List<LintCode> get lintCodes => const [
dartDirectiveGoFirst,
directiveSectionOrderedAlphabetically,
exportDirectiveAfterImportDirectives,
packageDirectiveBeforeRelative,
];
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {

View file

@ -337,6 +337,17 @@ class InvalidRuntimeCheckWithJSInteropTypes extends LintRule {
details: _details,
categories: {Category.error_prone});
@override
List<LintCode> get lintCodes => const [
dartTypeIsJsInteropTypeCode,
jsInteropTypeIsDartTypeCode,
jsInteropTypeIsInconsistentJsInteropType,
jsInteropTypeIsUnrelatedJsInteropTypeCode,
dartTypeAsJsInteropTypeCode,
jsInteropTypeAsDartTypeCode,
jsInteropTypeAsIncompatibleJsInteropTypeCode,
];
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {

View file

@ -9,7 +9,7 @@ import 'package:analyzer/dart/element/type.dart';
import '../analyzer.dart';
const _desc = r"Don't compare booleans to boolean literals.";
const _desc = r"Don't compare Boolean expressions to Boolean literals.";
const _details = r'''
From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-true-or-false-in-equality-operations):
@ -21,21 +21,30 @@ This lint applies only if the expression is of a non-nullable `bool` type.
**BAD:**
```dart
if (someBool == true) {
print('true!');
}
while (someBool == false) {
print('still false!');
}
```
**GOOD:**
```dart
if (someBool) {
print('true!');
}
while (!someBool) {
print('still false!');
}
```
''';
class NoLiteralBoolComparisons extends LintRule {
static const LintCode code = LintCode('no_literal_bool_comparisons', _desc,
correctionMessage:
'Try expressing the Boolean expression without the Boolean literal.',
hasPublishedDocs: true);
NoLiteralBoolComparisons()
: super(
name: 'no_literal_bool_comparisons',
@ -44,6 +53,9 @@ class NoLiteralBoolComparisons extends LintRule {
categories: {Category.style},
);
@override
LintCode get lintCode => code;
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {

View file

@ -76,6 +76,9 @@ class PreferTypingUninitializedVariables extends LintRule {
details: _details,
categories: {Category.error_prone, Category.unintentional});
@override
List<LintCode> get lintCodes => const [forField, forVariable];
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {

View file

@ -67,6 +67,9 @@ class UseSuperParameters extends LintRule {
state: State.experimental(),
categories: {Category.style});
@override
List<LintCode> get lintCodes => const [singleParam, multipleParams];
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {

View file

@ -40,7 +40,7 @@ void defineLinterEngineTests() {
test('pubspec', () {
var visited = false;
var options =
LinterOptions(enabledRules: [MockLinter((n) => visited = true)]);
LinterOptions(enabledRules: [MockLintRule((n) => visited = true)]);
TestLinter(options).lintPubspecSource(contents: 'name: foo_bar');
expect(visited, isTrue);
});
@ -62,9 +62,9 @@ void defineLinterEngineTests() {
typedef NodeVisitor = void Function(Object node);
class MockLinter extends LintRule {
class MockLintRule extends LintRule {
final NodeVisitor nodeVisitor;
MockLinter(this.nodeVisitor)
MockLintRule(this.nodeVisitor)
: super(
name: 'MockLint',
categories: {Category.style},

View file

@ -29,6 +29,11 @@ test_myTest() async {
''';
class NoSoloTests extends LintRule {
static const LintCode code = LintCode('no_solo_tests', _desc,
correctionMessage:
"Try removing the 'soloTest' annotation or 'solo_' prefix.",
hasPublishedDocs: true);
NoSoloTests()
: super(
name: 'no_solo_tests',
@ -36,6 +41,9 @@ class NoSoloTests extends LintRule {
details: _details,
categories: {Category.errors});
@override
LintCode get lintCode => code;
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {

View file

@ -8,10 +8,10 @@ import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:linter/src/analyzer.dart';
const _desc = r'Declare visit methods for all registered node types.';
const _desc = r"Declare 'visit' methods for all registered node types.";
const _details = r'''
**DO** declare a visit method for all registered node processors.
**DO** declare a 'visit' method for all registered node processors.
**BAD:**
```dart
@ -64,6 +64,11 @@ const _details = r'''
''';
class VisitRegisteredNodes extends LintRule {
static const LintCode code = LintCode('visit_registered_nodes', _desc,
correctionMessage:
"Try declaring a 'visit' method for all registered node types.",
hasPublishedDocs: true);
VisitRegisteredNodes()
: super(
name: 'visit_registered_nodes',
@ -71,6 +76,9 @@ class VisitRegisteredNodes extends LintRule {
details: _details,
categories: {Category.errors});
@override
LintCode get lintCode => code;
@override
void registerNodeProcessors(
NodeLintRegistry registry, LinterContext context) {