Merge branch 'main' into built-context-3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c924ca..f5997f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,10 @@
-1.35.0
+# 3.1.0-wip
+
+- new lint: `no_wildcard_variable_uses`
+
+---
+
+# 1.35.0
- add new lints:
- `implicit_reopen`
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index bd98b80..32ed681 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -63,6 +63,14 @@
Please make sure all your checkins have detailed commit messages explaining the patch and if a PR is *not* ready to land, consider making it clear in the description and/or prefixing the title with "WIP".
+Please note that a few kinds of changes require a `CHANGELOG` entry. Notably, any change that:
+
+1. adds a new lint
+2. removes or deprecates a lint or
+3. fundamentally changes the semantics of an existing lint
+
+should have a short entry in the `CHANGELOG`. Feel free to bring up any questions in your PR.
+
Once you've gotten an LGTM from a project maintainer, submit your changes to the
`main` branch using one of the following methods:
diff --git a/doc/lint-lifecycle.md b/doc/lint-lifecycle.md
index c9992ff..6b83785 100644
--- a/doc/lint-lifecycle.md
+++ b/doc/lint-lifecycle.md
@@ -50,6 +50,11 @@
## State Transitions
+### Implementation
+
+Once a lint proposal is accepted, it is safe to implement. A change that lands a new lint should
+have a corresponding `CHANGELOG` entry.
+
### Deprecation
Implemented lints can be deprecated.
@@ -57,6 +62,8 @@
Deprecating lints that are in common lint sets (e.g., in [package:lints](https://github.com/dart-lang/lints)
can be impactful so should be done with care.
+(**NOTE**: A change that deprecates an existing lint should have a corresponding `CHANGELOG` entry.)
+
### Marking Stable
Experimental lints should aspire to be stable. An experimental lint is a candidate for stable when it has
@@ -64,3 +71,9 @@
* complete semantics
* complete implementation (with no false-positives)
* established long-term value (e.g., inclusion in a recommended lint set)
+
+### Removal
+
+Deprecated or experimental lints can be removed. A stable lint should be deprecated before removal.
+
+(**NOTE**: A change that removes an existing lint should have a corresponding `CHANGELOG` entry.)
diff --git a/lib/src/rules.dart b/lib/src/rules.dart
index 6d027f6..5adcef4 100644
--- a/lib/src/rules.dart
+++ b/lib/src/rules.dart
@@ -66,7 +66,6 @@
import 'rules/control_flow_in_finally.dart';
import 'rules/curly_braces_in_flow_control_structures.dart';
import 'rules/dangling_library_doc_comments.dart';
-import 'rules/depend_on_referenced_packages.dart';
import 'rules/deprecated_consistency.dart';
import 'rules/deprecated_member_use_from_same_package.dart';
import 'rules/diagnostic_describe_all_properties.dart';
@@ -162,6 +161,7 @@
import 'rules/prefer_typing_uninitialized_variables.dart';
import 'rules/prefer_void_to_null.dart';
import 'rules/provide_deprecation_message.dart';
+import 'rules/pub/depend_on_referenced_packages.dart';
import 'rules/pub/package_names.dart';
import 'rules/pub/secure_pubspec_urls.dart';
import 'rules/pub/sort_pub_dependencies.dart';
@@ -235,7 +235,6 @@
Analyzer.facade.cacheLinterVersion();
Analyzer.facade
..register(AlwaysDeclareReturnTypes())
- ..register(UnnecessaryLibraryDirective())
..register(AlwaysPutControlBodyOnNewLine())
..register(AlwaysPutRequiredNamedParametersFirst())
..register(AlwaysRequireNonNullNamedParameters())
@@ -251,27 +250,27 @@
..register(AvoidDoubleAndIntChecks())
..register(AvoidDynamicCalls())
..register(AvoidEmptyElse())
+ ..register(AvoidEqualsAndHashCodeOnMutableClasses())
..register(AvoidEscapingInnerQuotes())
..register(AvoidFieldInitializersInConstClasses())
..register(AvoidFinalParameters())
- ..register(AvoidFunctionLiteralInForeachMethod())
+ ..register(AvoidFunctionLiteralsInForeachCalls())
..register(AvoidImplementingValueTypes())
..register(AvoidInitToNull())
..register(AvoidJsRoundedInts())
..register(AvoidMultipleDeclarationsPerLine())
..register(AvoidNullChecksInEqualityOperators())
- ..register(AvoidOperatorEqualsOnMutableClasses())
..register(AvoidPositionalBooleanParameters())
..register(AvoidPrint())
..register(AvoidPrivateTypedefFunctions())
..register(AvoidRedundantArgumentValues())
..register(AvoidRelativeLibImports())
..register(AvoidRenamingMethodParameters())
+ ..register(AvoidReturnTypesOnSetters())
..register(AvoidReturningNull())
..register(AvoidReturningNullForFuture())
..register(AvoidReturningNullForVoid())
..register(AvoidReturningThis())
- ..register(AvoidReturnTypesOnSetters())
..register(AvoidSettersWithoutGetters())
..register(AvoidShadowingTypeParameters())
..register(AvoidSingleCascadeInExpressionStatements())
@@ -301,7 +300,7 @@
..register(DependOnReferencedPackages())
..register(DeprecatedConsistency())
..register(DeprecatedMemberUseFromSamePackage())
- ..register(DiagnosticsDescribeAllProperties())
+ ..register(DiagnosticDescribeAllProperties())
..register(DirectivesOrdering())
..register(DiscardedFutures())
..register(DoNotUseEnvironment())
@@ -317,15 +316,15 @@
..register(ImplementationImports())
..register(ImplicitCallTearoffs())
..register(ImplicitReopen())
- ..register(InvariantBooleans())
..register(InvalidCasePatterns())
+ ..register(InvariantBooleans())
..register(IterableContainsUnrelatedType())
..register(JoinReturnWithAssignment())
..register(LeadingNewlinesInMultilineStrings())
..register(LibraryAnnotations())
..register(LibraryNames())
..register(LibraryPrefixes())
- ..register(LibraryPrivateTypesInPublicAPI())
+ ..register(LibraryPrivateTypesInPublicApi())
..register(LinesLongerThan80Chars())
..register(ListRemoveUnrelatedType())
..register(LiteralOnlyBooleanExpressions())
@@ -334,15 +333,15 @@
..register(NoAdjacentStringsInList())
..register(NoDefaultCases())
..register(NoDuplicateCaseValues())
- ..register(NoLiteralBoolComparisons())
- ..register(NonConstantIdentifierNames())
..register(NoLeadingUnderscoresForLibraryPrefixes())
..register(NoLeadingUnderscoresForLocalIdentifiers())
+ ..register(NoLiteralBoolComparisons())
..register(NoLogicInCreateState())
- ..register(NoopPrimitiveOperations())
..register(NoRuntimeTypeToString())
..register(NoSelfAssignments())
..register(NoWildcardVariableUses())
+ ..register(NonConstantIdentifierNames())
+ ..register(NoopPrimitiveOperations())
..register(NullCheckOnNullableTypeParameter())
..register(NullClosures())
..register(OmitLocalVariableTypes())
@@ -350,6 +349,7 @@
..register(OnlyThrowErrors())
..register(OverriddenFields())
..register(PackageApiDocs())
+ ..register(PackageNames())
..register(PackagePrefixedLibraryNames())
..register(ParameterAssignments())
..register(PreferAdjacentStringConcatenation())
@@ -362,8 +362,8 @@
..register(PreferConstConstructorsInImmutables())
..register(PreferConstDeclarations())
..register(PreferConstLiteralsToCreateImmutables())
- ..register(PreferConstructorsInsteadOfStaticMethods())
- ..register(PreferContainsOverIndexOf())
+ ..register(PreferConstructorsOverStaticMethods())
+ ..register(PreferContains())
..register(PreferDoubleQuotes())
..register(PreferEqualForDefaultValues())
..register(PreferExpressionFunctionBodies())
@@ -371,23 +371,23 @@
..register(PreferFinalInForEach())
..register(PreferFinalLocals())
..register(PreferFinalParameters())
- ..register(PreferForeach())
..register(PreferForElementsToMapFromIterable())
+ ..register(PreferForeach())
..register(PreferFunctionDeclarationsOverVariables())
..register(PreferGenericFunctionTypeAliases())
..register(PreferIfElementsToConditionalExpressions())
..register(PreferIfNullOperators())
..register(PreferInitializingFormals())
..register(PreferInlinedAdds())
- ..register(PreferInterpolationToComposeStrings())
..register(PreferIntLiterals())
+ ..register(PreferInterpolationToComposeStrings())
..register(PreferIsEmpty())
..register(PreferIsNotEmpty())
..register(PreferIsNotOperator())
..register(PreferIterableWhereType())
..register(PreferMixin())
- ..register(PreferNullAwareOperators())
..register(PreferNullAwareMethodCalls())
+ ..register(PreferNullAwareOperators())
..register(PreferRelativeImports())
..register(PreferSingleQuotes())
..register(PreferSpreadCollections())
@@ -395,10 +395,9 @@
..register(PreferVoidToNull())
..register(ProvideDeprecationMessage())
..register(PublicMemberApiDocs())
- ..register(PubPackageNames())
- ..register(SecurePubspecUrls())
..register(RecursiveGetters())
..register(RequireTrailingCommas())
+ ..register(SecurePubspecUrls())
..register(SizedBoxForWhitespace())
..register(SizedBoxShrinkExpand())
..register(SlashForDocComments())
@@ -408,8 +407,8 @@
..register(SortUnnamedConstructorsFirst())
..register(SuperGoesLast())
..register(TestTypesInEquals())
- ..register(TightenTypeOfInitializingFormals())
..register(ThrowInFinally())
+ ..register(TightenTypeOfInitializingFormals())
..register(TypeAnnotatePublicApis())
..register(TypeInitFormals())
..register(TypeLiteralInConstantPattern())
@@ -420,15 +419,16 @@
..register(UnnecessaryConst())
..register(UnnecessaryConstructorName())
..register(UnnecessaryFinal())
- ..register(UnnecessaryNew())
- ..register(UnnecessaryNullAwareAssignments())
- ..register(UnnecessaryNullInIfNullOperators())
..register(UnnecessaryGettersSetters())
..register(UnnecessaryLambdas())
..register(UnnecessaryLate())
- ..register(UnnecessaryNullableForFinalVariableDeclarations())
+ ..register(UnnecessaryLibraryDirective())
+ ..register(UnnecessaryNew())
+ ..register(UnnecessaryNullAwareAssignments())
..register(UnnecessaryNullAwareOperatorOnExtensionOnNullable())
..register(UnnecessaryNullChecks())
+ ..register(UnnecessaryNullInIfNullOperators())
+ ..register(UnnecessaryNullableForFinalVariableDeclarations())
..register(UnnecessaryOverrides())
..register(UnnecessaryParenthesis())
..register(UnnecessaryRawStrings())
@@ -447,18 +447,18 @@
..register(UseFullHexValuesForFlutterColors())
..register(UseFunctionTypeSyntaxForParameters())
..register(UseIfNullToConvertNullsToBools())
- ..register(UseIsEvenRatherThanModuloCheck())
+ ..register(UseIsEvenRatherThanModulo())
..register(UseKeyInWidgetConstructors())
..register(UseLateForPrivateFieldsAndVariables())
..register(UseNamedConstants())
- ..register(UseRethrowWhenPossible())
..register(UseRawStrings())
- ..register(UseSettersToChangeAProperty())
+ ..register(UseRethrowWhenPossible())
+ ..register(UseSettersToChangeProperties())
..register(UseStringBuffers())
..register(UseStringInPartOfDirectives())
..register(UseSuperParameters())
..register(UseTestThrowsMatchers())
..register(UseToAndAsIfApplicable())
- ..register(ValidRegExps())
+ ..register(ValidRegexps())
..register(VoidChecks());
}
diff --git a/lib/src/rules/avoid_equals_and_hash_code_on_mutable_classes.dart b/lib/src/rules/avoid_equals_and_hash_code_on_mutable_classes.dart
index 24e8b2a..ab6927d 100644
--- a/lib/src/rules/avoid_equals_and_hash_code_on_mutable_classes.dart
+++ b/lib/src/rules/avoid_equals_and_hash_code_on_mutable_classes.dart
@@ -74,14 +74,14 @@
element.name == _immutableVarName &&
element.library.name == _metaLibName;
-class AvoidOperatorEqualsOnMutableClasses extends LintRule {
+class AvoidEqualsAndHashCodeOnMutableClasses extends LintRule {
static const LintCode code = LintCode(
'avoid_equals_and_hash_code_on_mutable_classes',
- "The method '{0}' should not be overriden in classes not annotated with '@immutable'.",
+ "The method '{0}' should not be overridden in classes not annotated with '@immutable'.",
correctionMessage:
"Try removing the override or annotating the class with '@immutable'.");
- AvoidOperatorEqualsOnMutableClasses()
+ AvoidEqualsAndHashCodeOnMutableClasses()
: super(
name: 'avoid_equals_and_hash_code_on_mutable_classes',
description: _desc,
diff --git a/lib/src/rules/avoid_function_literals_in_foreach_calls.dart b/lib/src/rules/avoid_function_literals_in_foreach_calls.dart
index 870696e..1e9a7ff 100644
--- a/lib/src/rules/avoid_function_literals_in_foreach_calls.dart
+++ b/lib/src/rules/avoid_function_literals_in_foreach_calls.dart
@@ -58,13 +58,13 @@
bool _isIterable(DartType? type) =>
type != null && type.implementsInterface('Iterable', 'dart.core');
-class AvoidFunctionLiteralInForeachMethod extends LintRule {
+class AvoidFunctionLiteralsInForeachCalls extends LintRule {
static const LintCode code = LintCode(
'avoid_function_literals_in_foreach_calls',
"Function literals shouldn't be passed to 'forEach'.",
correctionMessage: "Try using a 'for' loop.");
- AvoidFunctionLiteralInForeachMethod()
+ AvoidFunctionLiteralsInForeachCalls()
: super(
name: 'avoid_function_literals_in_foreach_calls',
description: _desc,
diff --git a/lib/src/rules/diagnostic_describe_all_properties.dart b/lib/src/rules/diagnostic_describe_all_properties.dart
index 196d1fc..e4ccdb5 100644
--- a/lib/src/rules/diagnostic_describe_all_properties.dart
+++ b/lib/src/rules/diagnostic_describe_all_properties.dart
@@ -66,14 +66,14 @@
```
''';
-class DiagnosticsDescribeAllProperties extends LintRule {
+class DiagnosticDescribeAllProperties extends LintRule {
static const LintCode code = LintCode(
'diagnostic_describe_all_properties',
"The public property isn't described by either 'debugFillProperties' or "
"'debugDescribeChildren'.",
correctionMessage: 'Try describing the property.');
- DiagnosticsDescribeAllProperties()
+ DiagnosticDescribeAllProperties()
: super(
name: 'diagnostic_describe_all_properties',
description: _desc,
diff --git a/lib/src/rules/library_private_types_in_public_api.dart b/lib/src/rules/library_private_types_in_public_api.dart
index 432c39d..114a3d4 100644
--- a/lib/src/rules/library_private_types_in_public_api.dart
+++ b/lib/src/rules/library_private_types_in_public_api.dart
@@ -40,14 +40,14 @@
''';
-class LibraryPrivateTypesInPublicAPI extends LintRule {
+class LibraryPrivateTypesInPublicApi extends LintRule {
static const LintCode code = LintCode('library_private_types_in_public_api',
'Invalid use of a private type in a public API.',
correctionMessage:
'Try making the private type public, or making the API that uses the '
'private type also be private.');
- LibraryPrivateTypesInPublicAPI()
+ LibraryPrivateTypesInPublicApi()
: super(
name: 'library_private_types_in_public_api',
description: _desc,
diff --git a/lib/src/rules/prefer_constructors_over_static_methods.dart b/lib/src/rules/prefer_constructors_over_static_methods.dart
index c186a81..b86bb5e 100644
--- a/lib/src/rules/prefer_constructors_over_static_methods.dart
+++ b/lib/src/rules/prefer_constructors_over_static_methods.dart
@@ -44,13 +44,18 @@
bool _hasNewInvocation(DartType returnType, FunctionBody body) =>
_BodyVisitor(returnType).containsInstanceCreation(body);
-class PreferConstructorsInsteadOfStaticMethods extends LintRule {
+// todo(pq): temporary; remove after renamed class is in the SDK
+// ignore: non_constant_identifier_names
+LintRule PreferConstructorsInsteadOfStaticMethods() =>
+ PreferConstructorsOverStaticMethods();
+
+class PreferConstructorsOverStaticMethods extends LintRule {
static const LintCode code = LintCode(
'prefer_constructors_over_static_methods',
'Static method should be a constructor.',
correctionMessage: 'Try converting the method into a constructor.');
- PreferConstructorsInsteadOfStaticMethods()
+ PreferConstructorsOverStaticMethods()
: super(
name: 'prefer_constructors_over_static_methods',
description: _desc,
diff --git a/lib/src/rules/prefer_contains.dart b/lib/src/rules/prefer_contains.dart
index ff96590..fb535ac 100644
--- a/lib/src/rules/prefer_contains.dart
+++ b/lib/src/rules/prefer_contains.dart
@@ -32,7 +32,7 @@
''';
-class PreferContainsOverIndexOf extends LintRule {
+class PreferContains extends LintRule {
// TODO(brianwilkerson) Both `alwaysFalse` and `alwaysTrue` should be warnings
// rather than lints because they represent a bug rather than a style
// preference.
@@ -46,7 +46,7 @@
"Unnecessary use of 'indexOf' to test for containment.",
correctionMessage: "Try using 'contains'.");
- PreferContainsOverIndexOf()
+ PreferContains()
: super(
name: 'prefer_contains',
description: _desc,
@@ -65,7 +65,7 @@
}
class _Visitor extends SimpleAstVisitor<void> {
- final PreferContainsOverIndexOf rule;
+ final PreferContains rule;
final LinterContext context;
@@ -105,23 +105,19 @@
type == TokenType.BANG_EQ ||
type == TokenType.LT_EQ ||
type == TokenType.GT) {
- rule.reportLint(expression,
- errorCode: PreferContainsOverIndexOf.useContains);
+ rule.reportLint(expression, errorCode: PreferContains.useContains);
} else if (type == TokenType.LT) {
// indexOf < -1 is always false
- rule.reportLint(expression,
- errorCode: PreferContainsOverIndexOf.alwaysFalse);
+ rule.reportLint(expression, errorCode: PreferContains.alwaysFalse);
} else if (type == TokenType.GT_EQ) {
// indexOf >= -1 is always true
- rule.reportLint(expression,
- errorCode: PreferContainsOverIndexOf.alwaysTrue);
+ rule.reportLint(expression, errorCode: PreferContains.alwaysTrue);
}
} else if (value == 0) {
// 'indexOf >= 0' is same as 'contains',
// and 'indexOf < 0' is same as '!contains'
if (type == TokenType.GT_EQ || type == TokenType.LT) {
- rule.reportLint(expression,
- errorCode: PreferContainsOverIndexOf.useContains);
+ rule.reportLint(expression, errorCode: PreferContains.useContains);
}
} else if (value < -1) {
// 'indexOf' is always >= -1, so comparing with lesser values makes
@@ -129,13 +125,11 @@
if (type == TokenType.EQ_EQ ||
type == TokenType.LT_EQ ||
type == TokenType.LT) {
- rule.reportLint(expression,
- errorCode: PreferContainsOverIndexOf.alwaysFalse);
+ rule.reportLint(expression, errorCode: PreferContains.alwaysFalse);
} else if (type == TokenType.BANG_EQ ||
type == TokenType.GT_EQ ||
type == TokenType.GT) {
- rule.reportLint(expression,
- errorCode: PreferContainsOverIndexOf.alwaysTrue);
+ rule.reportLint(expression, errorCode: PreferContains.alwaysTrue);
}
}
}
diff --git a/lib/src/rules/depend_on_referenced_packages.dart b/lib/src/rules/pub/depend_on_referenced_packages.dart
similarity index 98%
rename from lib/src/rules/depend_on_referenced_packages.dart
rename to lib/src/rules/pub/depend_on_referenced_packages.dart
index ed9b21c..ab344dc 100644
--- a/lib/src/rules/depend_on_referenced_packages.dart
+++ b/lib/src/rules/pub/depend_on_referenced_packages.dart
@@ -5,8 +5,8 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
-import '../analyzer.dart';
-import '../ast.dart';
+import '../../analyzer.dart';
+import '../../ast.dart';
const _desc = r'Depend on referenced packages.';
diff --git a/lib/src/rules/pub/package_names.dart b/lib/src/rules/pub/package_names.dart
index f452a02..bb674c2 100644
--- a/lib/src/rules/pub/package_names.dart
+++ b/lib/src/rules/pub/package_names.dart
@@ -19,13 +19,13 @@
''';
-class PubPackageNames extends LintRule {
+class PackageNames extends LintRule {
static const LintCode code = LintCode(
'package_names', "The package name '{0}' isn't a snake_case identifier.",
correctionMessage:
'Try changing the name to follow the snake_case style.');
- PubPackageNames()
+ PackageNames()
: super(
name: 'package_names',
description: _desc,
diff --git a/lib/src/rules/use_is_even_rather_than_modulo.dart b/lib/src/rules/use_is_even_rather_than_modulo.dart
index eedae6a..14cdd8b 100644
--- a/lib/src/rules/use_is_even_rather_than_modulo.dart
+++ b/lib/src/rules/use_is_even_rather_than_modulo.dart
@@ -28,12 +28,12 @@
''';
-class UseIsEvenRatherThanModuloCheck extends LintRule {
+class UseIsEvenRatherThanModulo extends LintRule {
static const LintCode code = LintCode(
'use_is_even_rather_than_modulo', "Use '{0}' rather than '% 2'.",
correctionMessage: "Try using '{0}'.");
- UseIsEvenRatherThanModuloCheck()
+ UseIsEvenRatherThanModulo()
: super(
name: 'use_is_even_rather_than_modulo',
description: _desc,
diff --git a/lib/src/rules/use_setters_to_change_properties.dart b/lib/src/rules/use_setters_to_change_properties.dart
index a7df4b4..fdc504d 100644
--- a/lib/src/rules/use_setters_to_change_properties.dart
+++ b/lib/src/rules/use_setters_to_change_properties.dart
@@ -31,12 +31,16 @@
''';
-class UseSettersToChangeAProperty extends LintRule {
+// todo(pq): temporary; remove after renamed class is in the SDK
+// ignore: non_constant_identifier_names
+UseSettersToChangeAProperty() => UseSettersToChangeProperties();
+
+class UseSettersToChangeProperties extends LintRule {
static const LintCode code = LintCode('use_setters_to_change_properties',
'The method is used to change a property.',
correctionMessage: 'Try converting the method to a setter.');
- UseSettersToChangeAProperty()
+ UseSettersToChangeProperties()
: super(
name: 'use_setters_to_change_properties',
description: _desc,
diff --git a/lib/src/rules/valid_regexps.dart b/lib/src/rules/valid_regexps.dart
index 0c9675f..a09b0a0 100644
--- a/lib/src/rules/valid_regexps.dart
+++ b/lib/src/rules/valid_regexps.dart
@@ -28,12 +28,12 @@
''';
-class ValidRegExps extends LintRule {
+class ValidRegexps extends LintRule {
static const LintCode code = LintCode(
'valid_regexps', 'Invalid regular expression syntax.',
correctionMessage: 'Try correcting the regular expression.');
- ValidRegExps()
+ ValidRegexps()
: super(
name: 'valid_regexps',
description: _desc,
diff --git a/pubspec.yaml b/pubspec.yaml
index 0761c4b..c7698ec 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,8 +1,6 @@
name: linter
# This package is not intended for consumption on pub.dev. DO NOT publish.
publish_to: none
-# TODO (pq): remove (https://github.com/dart-lang/linter/issues/4389)
-version: 1.35.0
description: >-
The implementation of the lint rules supported by the analyzer framework.
diff --git a/test/rules/all.dart b/test/rules/all.dart
index bad6a64..6e1c9ef 100644
--- a/test/rules/all.dart
+++ b/test/rules/all.dart
@@ -72,7 +72,7 @@
as no_leading_underscores_for_local_identifiers;
import 'no_self_assignments_test.dart' as no_self_assignments;
import 'no_wildcard_variable_uses_test.dart' as no_wildcard_variable_uses;
-import 'non_adjacent_strings_in_list_test.dart' as no_adjacent_strings_in_list;
+import 'non_adjacent_strings_in_list_test.dart' as non_adjacent_strings_in_list;
import 'non_constant_identifier_names_test.dart'
as non_constant_identifier_names;
import 'null_check_on_nullable_type_parameter_test.dart'
@@ -159,8 +159,8 @@
avoid_annotating_with_dynamic.main();
avoid_equals_and_hash_code_on_mutable_classes.main();
avoid_escaping_inner_quotes.main();
- avoid_function_literals_in_foreach_calls.main();
avoid_final_parameters.main();
+ avoid_function_literals_in_foreach_calls.main();
avoid_init_to_null.main();
avoid_private_typedef_functions.main();
avoid_redundant_argument_values.main();
@@ -199,11 +199,11 @@
literal_only_boolean_expressions.main();
matching_super_parameters.main();
missing_whitespace_between_adjacent_strings.main();
- no_adjacent_strings_in_list.main();
no_duplicate_case_values.main();
no_leading_underscores_for_local_identifiers.main();
no_self_assignments.main();
no_wildcard_variable_uses.main();
+ non_adjacent_strings_in_list.main();
non_constant_identifier_names.main();
null_check_on_nullable_type_parameter.main();
null_closures.main();
@@ -214,8 +214,8 @@
parameter_assignments.main();
prefer_asserts_in_initializer_lists.main();
prefer_collection_literals.main();
- prefer_const_constructors.main();
prefer_const_constructors_in_immutables.main();
+ prefer_const_constructors.main();
prefer_const_declarations.main();
prefer_const_literals_to_create_immutables.main();
prefer_constructors_over_static_methods.main();
@@ -226,11 +226,11 @@
prefer_final_locals.main();
prefer_final_parameters.main();
prefer_generic_function_type_aliases.main();
+ prefer_mixin.main();
prefer_relative_imports.main();
prefer_spread_collections.main();
- public_member_api_docs.main();
- prefer_mixin.main();
prefer_void_to_null.main();
+ public_member_api_docs.main();
recursive_getters.main();
secure_pubspec_urls.main();
sort_constructors_first.main();
@@ -246,8 +246,8 @@
unnecessary_final.main();
unnecessary_lambdas.main();
unnecessary_library_directive.main();
- unnecessary_nullable_for_final_variable_declarations.main();
unnecessary_null_checks.main();
+ unnecessary_nullable_for_final_variable_declarations.main();
unnecessary_overrides.main();
unnecessary_parenthesis.main();
unnecessary_statements.main();
diff --git a/tool/rule.dart b/tool/rule.dart
index 2a384d9..a6ad5fb 100644
--- a/tool/rule.dart
+++ b/tool/rule.dart
@@ -4,13 +4,17 @@
import 'dart:io';
+import 'package:analyzer/src/lint/registry.dart';
+import 'package:analyzer/src/lint/state.dart';
import 'package:args/args.dart';
+import 'package:linter/src/analyzer.dart';
+import 'package:linter/src/rules.dart';
import 'package:linter/src/utils.dart';
import 'package:path/path.dart' as path;
import '../test/test_constants.dart';
-/// Generates rule and rule test stub files (into `src/rules` and `test_data/rules`
+/// Generates rule and rule test stub files (into `src/rules` and `test/rules`
/// respectively), as well as the rule index (`rules.dart`).
void main(List<String> args) {
var parser = ArgParser()
@@ -44,46 +48,60 @@
return;
}
- // Generate rule stub.
+ // Generate rule stub and update supporting files.
generateRule(ruleName as String, outDir: outDir);
}
+var _supportsTestMode = ['use_build_context_synchronously'];
+
String get _thisYear => DateTime.now().year.toString();
String capitalize(String s) => s.substring(0, 1).toUpperCase() + s.substring(1);
-void generateRule(String ruleName, {String? outDir}) {
- // Generate rule stub.
- generateStub(ruleName, path.join('lib', 'src', 'rules'), _generateClass,
- outDir: outDir);
-
- // Generate test stub.
- generateStub(ruleName, ruleTestDir, _generateTest, outDir: outDir);
-
- // Update rule registry.
- updateRuleRegistry(ruleName);
-
- printToConsole('A unit test has been stubbed out in:');
- printToConsole(' $ruleTestDir/${ruleName}_test.dart');
-}
-
-void generateStub(String ruleName, String stubPath, Generator generator,
- {String? outDir}) {
+void generateFile(String ruleName, String stubPath, Generator generator,
+ {String? outDir, bool overwrite = false, bool format = false}) {
var (:file, :contents) = generator(ruleName, toClassName(ruleName));
if (outDir != null) {
var outPath = path.join(outDir, stubPath, file);
var outFile = File(outPath);
- if (outFile.existsSync()) {
+ if (!overwrite && outFile.existsSync()) {
printToConsole('Warning: stub already exists at $outPath; skipping');
return;
}
printToConsole('Writing to $outPath');
outFile.writeAsStringSync(contents);
+ if (format) {
+ Process.runSync('dart', ['format', '-o', 'write', outPath]);
+ }
} else {
printToConsole(contents);
}
}
+void generateRule(String ruleName, {String? outDir}) {
+ // Generate rule stub.
+ generateFile(ruleName, path.join('lib', 'src', 'rules'), _generateClass,
+ outDir: outDir);
+
+ // Generate unit test stub.
+ generateFile(ruleName, ruleTestDir, _generateTest, outDir: outDir);
+
+ // Generate test `all.dart` helper.
+ generateFile(ruleName, ruleTestDir, _generateAllTestsFile,
+ outDir: outDir, overwrite: true, format: true);
+
+ // Generate an example `all.yaml`
+ generateFile(ruleName, 'example', _generateAllYaml,
+ outDir: outDir, overwrite: true);
+
+ // Update rule registry.
+ generateFile(ruleName, path.join('lib', 'src'), _generateRulesFile,
+ outDir: outDir, overwrite: true);
+
+ printToConsole('A unit test has been stubbed out in:');
+ printToConsole(' $ruleTestDir/${ruleName}_test.dart');
+}
+
void printUsage(ArgParser parser, [String? error]) {
var message = error ?? 'Generates rule stubs.';
@@ -96,10 +114,60 @@
String toClassName(String ruleName) =>
ruleName.split('_').map(capitalize).join();
-void updateRuleRegistry(String ruleName) {
- printToConsole("Don't forget to update lib/src/rules.dart with a line like:");
- printToConsole(' ..register(${toClassName(ruleName)}())');
- printToConsole('and add your rule to `example/all.yaml`.');
+GeneratedFile _generateAllTestsFile(String libName, String className) {
+ registerLintRules();
+ var sb = StringBuffer();
+ sb.write('''
+// Copyright (c) 2021, 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.
+
+''');
+
+ var paths = Directory(ruleTestDir).listSync().map((f) => f.path).toList()
+ ..sort();
+
+ var testNames = <String>[];
+ for (var file in paths) {
+ if (!file.endsWith('_test.dart')) continue;
+ var filePath = path.relative(file, from: path.join('test', 'rules'));
+ var testName = path.split(filePath).last.split('_test').first;
+ testNames.add(testName);
+ sb.writeln("import '$filePath' as $testName;");
+ }
+
+ sb.write(r'''
+
+void main() {
+''');
+ for (var testName in testNames) {
+ sb.writeln(' $testName.main();');
+ }
+ sb.writeln('}');
+ return (file: 'all.dart', contents: sb.toString());
+}
+
+GeneratedFile _generateAllYaml(String libName, String className) {
+ registerLintRules();
+ var sb = StringBuffer();
+ sb.write('''
+# Auto-generated options enabling all lints.
+# Add these to your `analysis_options.yaml` file and tailor to fit!
+linter:
+ rules:
+''');
+
+ var names = Registry.ruleRegistry.rules
+ .where((r) => !r.state.isDeprecated && !r.state.isRemoved)
+ .map((r) => r.name)
+ .toList();
+ names.add(libName);
+ names.sort();
+
+ for (var rule in names) {
+ sb.writeln(' - $rule');
+ }
+ return (file: 'all.yaml', contents: sb.toString());
}
GeneratedFile _generateClass(String ruleName, String className) => (
@@ -166,6 +234,51 @@
"""
);
+GeneratedFile _generateRulesFile(String libName, String className) {
+ registerLintRules();
+ var sb = StringBuffer();
+ sb.write('''
+// Copyright (c) 2015, 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 'analyzer.dart';
+''');
+
+ var names = Registry.ruleRegistry.rules.map((r) => r.name).toList();
+ names.add(libName);
+ names.sort();
+
+ var imports = <String>[];
+ for (var name in names) {
+ var pathPrefix = Registry.ruleRegistry.getRule(name)?.group == Group.pub
+ ? path.join('rules', 'pub')
+ : 'rules';
+ imports.add("import '$pathPrefix/$name.dart';");
+ }
+
+ //ignore: prefer_foreach
+ for (var import in imports..sort()) {
+ sb.writeln(import);
+ }
+
+ sb.write('''
+
+void registerLintRules({bool inTestMode = false}) {
+ Analyzer.facade.cacheLinterVersion();
+ Analyzer.facade
+''');
+
+ for (var (i, name) in names.indexed) {
+ var className = toClassName(name);
+ var args = _supportsTestMode.contains(name) ? 'inTestMode: inTestMode' : '';
+ var suffix = i == names.length - 1 ? ';' : '';
+ sb.writeln(' ..register($className($args))$suffix');
+ }
+ sb.writeln('}');
+ return (file: 'rules.dart', contents: sb.toString());
+}
+
GeneratedFile _generateTest(String libName, String className) => (
file: '${libName}_test.dart',
contents: '''