Skip to content

Commit

Permalink
[analyzer/linter] Surface links to available lint diagnostic messages
Browse files Browse the repository at this point in the history
Dependent on dart-lang/site-www#5914 landing first.

Bug: dart-lang/site-www#4498
Change-Id: I378debd5d484e17f18d59c49173a5d010f05b6df
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/371785
Commit-Queue: Brian Wilkerson <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
Reviewed-by: Sam Rawlins <[email protected]>
  • Loading branch information
parlough authored and Commit Queue committed Jun 17, 2024
1 parent 5641607 commit 91254e4
Show file tree
Hide file tree
Showing 117 changed files with 276 additions and 164 deletions.
9 changes: 3 additions & 6 deletions pkg/analyzer/lib/src/dart/error/lint_codes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@ import 'package:analyzer/error/error.dart';
/// compiler, lint recommendations focus on matters of style and practices that
/// might aggregated to define a project's style guide.
class LintCode extends ErrorCode {
final String? _url;

const LintCode(
String name,
String problemMessage, {
super.correctionMessage,
super.hasPublishedDocs,
String? uniqueName,
String? url,
}) : _url = url,
super(
}) : super(
problemMessage: problemMessage,
name: name,
uniqueName: uniqueName ?? 'LintCode.$name',
Expand All @@ -35,7 +32,7 @@ class LintCode extends ErrorCode {
ErrorType get type => ErrorType.LINT;

@override
String get url => _url ?? 'https://dart.dev/lints/$name';
String get url => super.url ?? 'https://dart.dev/lints/$name';

@override
bool operator ==(Object other) =>
Expand Down
5 changes: 0 additions & 5 deletions pkg/analyzer/lib/src/lint/linter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,6 @@ abstract class LintRule {
/// `bin`.
final String? documentation;

/// A flag indicating whether this lint has documentation on the Diagnostic
/// messages page.
final bool hasDocumentation;

/// The state of a lint, and optionally since when the state began.
final State state;

Expand All @@ -225,7 +221,6 @@ abstract class LintRule {
required this.details,
State? state,
this.documentation,
this.hasDocumentation = false,
}) : state = state ?? State.stable();

/// Indicates whether the lint rule can work with just the parsed information
Expand Down
16 changes: 16 additions & 0 deletions pkg/analyzer/test/src/lint/lint_rule_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ import '../../generated/test_support.dart';

main() {
group('lint rule', () {
group('code creation', () {
test('without published diagnostic docs', () {
expect(customCode.url,
equals('https://dart.dev/lints/${customCode.name}'));
});

test('with published diagnostic docs', () {
expect(customCodeWithDocs.url,
equals('https://dart.dev/diagnostics/${customCodeWithDocs.name}'));
});
});

group('error code reporting', () {
test('reportLintForToken (custom)', () {
var rule = TestRule();
Expand Down Expand Up @@ -70,6 +82,10 @@ const LintCode customCode = LintCode(
'hash_and_equals', 'Override `==` if overriding `hashCode`.',
correctionMessage: 'Implement `==`.');

const LintCode customCodeWithDocs = LintCode(
'hash_and_equals', 'Override `==` if overriding `hashCode`.',
correctionMessage: 'Implement `==`.', hasPublishedDocs: true);

class CollectingReporter extends ErrorReporter {
ErrorCode? code;

Expand Down
4 changes: 3 additions & 1 deletion pkg/analyzer/tool/diagnostics/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -24204,7 +24204,9 @@ Iterable<String> get zero sync* {

### always_declare_return_types

_Missing return type on method._
_The function '{0}' should have a return type but doesn't._

_The method '{0}' should have a return type but doesn't._

#### Description

Expand Down
35 changes: 16 additions & 19 deletions pkg/linter/lib/src/rules/always_declare_return_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,15 @@ typedef predicate = bool Function(Object o);
''';

class AlwaysDeclareReturnTypes extends LintRule {
static const LintCode code = LintCode(
'always_declare_return_types', 'Missing return type on method.',
correctionMessage: 'Try adding a return type.');
static const LintCode functionCode = LintCode('always_declare_return_types',
"The function '{0}' should have a return type but doesn't.",
correctionMessage: 'Try adding a return type to the function.',
hasPublishedDocs: true);

static const LintCode methodCode = LintCode('always_declare_return_types',
"The method '{0}' should have a return type but doesn't.",
correctionMessage: 'Try adding a return type to the method.',
hasPublishedDocs: true);

AlwaysDeclareReturnTypes()
: super(
Expand All @@ -58,7 +64,7 @@ class AlwaysDeclareReturnTypes extends LintRule {
categories: {Category.style});

@override
LintCode get lintCode => code;
List<LintCode> get lintCodes => [functionCode, methodCode];

@override
void registerNodeProcessors(
Expand All @@ -71,18 +77,6 @@ class AlwaysDeclareReturnTypes extends LintRule {
}

class _Visitor extends SimpleAstVisitor<void> {
static const LintCode functionCode = LintCode(
"always_declare_return_types", // ignore: prefer_single_quotes
"The function '{0}' should have a return type but doesn't.",
correctionMessage:
"Try adding a return type to the function."); // ignore: prefer_single_quotes

static const LintCode methodCode = LintCode(
"always_declare_return_types", // ignore: prefer_single_quotes
"The method '{0}' should have a return type but doesn't.",
correctionMessage:
"Try adding a return type to the method."); // ignore: prefer_single_quotes

final LintRule rule;

_Visitor(this.rule);
Expand All @@ -91,15 +85,17 @@ class _Visitor extends SimpleAstVisitor<void> {
void visitFunctionDeclaration(FunctionDeclaration node) {
if (!node.isSetter && node.returnType == null && !node.isAugmentation) {
rule.reportLintForToken(node.name,
arguments: [node.name.lexeme], errorCode: functionCode);
arguments: [node.name.lexeme],
errorCode: AlwaysDeclareReturnTypes.functionCode);
}
}

@override
void visitFunctionTypeAlias(FunctionTypeAlias node) {
if (node.returnType == null) {
rule.reportLintForToken(node.name,
arguments: [node.name.lexeme], errorCode: functionCode);
arguments: [node.name.lexeme],
errorCode: AlwaysDeclareReturnTypes.functionCode);
}
}

Expand All @@ -110,7 +106,8 @@ class _Visitor extends SimpleAstVisitor<void> {
node.name.type != TokenType.INDEX_EQ &&
!node.isAugmentation) {
rule.reportLintForToken(node.name,
arguments: [node.name.lexeme], errorCode: methodCode);
arguments: [node.name.lexeme],
errorCode: AlwaysDeclareReturnTypes.methodCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ when the Dart formatter is used.
class AlwaysPutControlBodyOnNewLine extends LintRule {
static const LintCode code = LintCode('always_put_control_body_on_new_line',
'Statement should be on a separate line.',
correctionMessage: 'Try moving the statement to a new line.');
correctionMessage: 'Try moving the statement to a new line.',
hasPublishedDocs: true);

AlwaysPutControlBodyOnNewLine()
: super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class AlwaysPutRequiredNamedParametersFirst extends LintRule {
'Required named parameters should be before optional named parameters.',
correctionMessage:
'Try moving the required named parameter to be before any optional '
'named parameters.');
'named parameters.',
hasPublishedDocs: true);

AlwaysPutRequiredNamedParametersFirst()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/always_use_package_imports.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ import 'package:foo/src/baz.dart';
class AlwaysUsePackageImports extends LintRule {
static const LintCode code = LintCode('always_use_package_imports',
"Use 'package:' imports for files in the 'lib' directory.",
correctionMessage: "Try converting the URI to a 'package:' URI.");
correctionMessage: "Try converting the URI to a 'package:' URI.",
hasPublishedDocs: true);

AlwaysUsePackageImports()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/annotate_overrides.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class AnnotateOverrides extends LintRule {
'annotate_overrides',
"The member '{0}' overrides an inherited member but isn't annotated "
"with '@override'.",
correctionMessage: "Try adding the '@override' annotation.");
correctionMessage: "Try adding the '@override' annotation.",
hasPublishedDocs: true);

AnnotateOverrides()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_empty_else.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class AvoidEmptyElse extends LintRule {
static const LintCode code = LintCode('avoid_empty_else',
"Empty statements are not allowed in an 'else' clause.",
correctionMessage:
'Try removing the empty statement or removing the else clause.');
'Try removing the empty statement or removing the else clause.',
hasPublishedDocs: true);

AvoidEmptyElse()
: super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ 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.");
correctionMessage: "Try using a 'for' loop.",
hasPublishedDocs: true);

AvoidFunctionLiteralsInForeachCalls()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_init_to_null.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ Item? bestDeal(List<Item> cart) {
class AvoidInitToNull extends LintRule {
static const LintCode code = LintCode(
'avoid_init_to_null', "Redundant initialization to 'null'.",
correctionMessage: 'Try removing the initializer.');
correctionMessage: 'Try removing the initializer.',
hasPublishedDocs: true);

AvoidInitToNull()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_print.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ void f(int x) {
class AvoidPrint extends LintRule {
static const LintCode code = LintCode(
'avoid_print', "Don't invoke 'print' in production code.",
correctionMessage: 'Try using a logging framework.');
correctionMessage: 'Try using a logging framework.',
hasPublishedDocs: true);

AvoidPrint()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_relative_lib_imports.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class AvoidRelativeLibImports extends LintRule {
"Can't use a relative path to import a library in 'lib'.",
correctionMessage:
"Try fixing the relative path or changing the import to a 'package:' "
'import.');
'import.',
hasPublishedDocs: true);

AvoidRelativeLibImports()
: super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class AvoidRenamingMethodParameters extends LintRule {
'avoid_renaming_method_parameters',
"The parameter name '{0}' doesn't match the name '{1}' in the overridden "
'method.',
correctionMessage: "Try changing the name to '{1}'.");
correctionMessage: "Try changing the name to '{1}'.",
hasPublishedDocs: true);

AvoidRenamingMethodParameters()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_return_types_on_setters.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ set speed(int ms);
class AvoidReturnTypesOnSetters extends LintRule {
static const LintCode code = LintCode(
'avoid_return_types_on_setters', 'Unnecessary return type on a setter.',
correctionMessage: 'Try removing the return type.');
correctionMessage: 'Try removing the return type.',
hasPublishedDocs: true);

AvoidReturnTypesOnSetters()
: super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class AvoidReturningNullForVoid extends LintRule {

static const LintCode fromMethod = LintCode('avoid_returning_null_for_void',
"Don't return 'null' from a method with a return type of 'void'.",
correctionMessage: "Try removing the 'null'.");
correctionMessage: "Try removing the 'null'.", hasPublishedDocs: true);

AvoidReturningNullForVoid()
: super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class A<T> {
class AvoidShadowingTypeParameters extends LintRule {
static const LintCode code = LintCode('avoid_shadowing_type_parameters',
"The type parameter '{0}' shadows a type parameter from the enclosing {1}.",
correctionMessage: 'Try renaming one of the type parameters.');
correctionMessage: 'Try renaming one of the type parameters.',
hasPublishedDocs: true);

AvoidShadowingTypeParameters()
: super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class AvoidSingleCascadeInExpressionStatements extends LintRule {
static const LintCode code = LintCode(
'avoid_single_cascade_in_expression_statements',
'Unnecessary cascade expression.',
correctionMessage: "Try using the operator '{0}'.");
correctionMessage: "Try using the operator '{0}'.",
hasPublishedDocs: true);

AvoidSingleCascadeInExpressionStatements()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_slow_async_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ const List<String> _fileSystemEntityMethodNames = <String>[
class AvoidSlowAsyncIo extends LintRule {
static const LintCode code = LintCode(
'avoid_slow_async_io', "Use of an async 'dart:io' method.",
correctionMessage: 'Try using the synchronous version of the method.');
correctionMessage: 'Try using the synchronous version of the method.',
hasPublishedDocs: true);

AvoidSlowAsyncIo()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_type_to_string.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ Object baz(Thing myThing) {

class AvoidTypeToString extends LintRule {
static const LintCode code = LintCode('avoid_type_to_string',
"Using 'toString' on a 'Type' is not safe in production code.");
"Using 'toString' on a 'Type' is not safe in production code.",
hasPublishedDocs: true);

AvoidTypeToString()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_types_as_parameter_names.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class AvoidTypesAsParameterNames extends LintRule {
"The parameter name '{0}' matches a visible type name.",
correctionMessage:
'Try adding a name for the parameter or changing the parameter name '
'to not match an existing type.');
'to not match an existing type.',
hasPublishedDocs: true);

AvoidTypesAsParameterNames()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_unnecessary_containers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class AvoidUnnecessaryContainers extends LintRule {
'avoid_unnecessary_containers', "Unnecessary instance of 'Container'.",
correctionMessage:
"Try removing the 'Container' (but not its children) from the "
'widget tree.');
'widget tree.',
hasPublishedDocs: true);

AvoidUnnecessaryContainers()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/avoid_web_libraries_in_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ YamlMap _parseYaml(String content) {
class AvoidWebLibrariesInFlutter extends LintRule {
static const LintCode code = LintCode('avoid_web_libraries_in_flutter',
"Don't use web-only libraries outside Flutter web plugin packages.",
correctionMessage: 'Try finding a different library for your needs.');
correctionMessage: 'Try finding a different library for your needs.',
hasPublishedDocs: true);

/// Cache of most recent analysis root to parsed "hasFlutter" state.
static final Map<String, bool> _rootHasFlutterCache = {};
Expand Down
4 changes: 2 additions & 2 deletions pkg/linter/lib/src/rules/await_only_futures.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ main() async {
class AwaitOnlyFutures extends LintRule {
static const LintCode code = LintCode('await_only_futures',
"Uses 'await' on an instance of '{0}', which is not a subtype of 'Future'.",
correctionMessage:
"Try removing the 'await' or changing the expression.");
correctionMessage: "Try removing the 'await' or changing the expression.",
hasPublishedDocs: true);

AwaitOnlyFutures()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/camel_case_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class CamelCaseExtensions extends LintRule {
static const LintCode code = LintCode('camel_case_extensions',
"The extension name '{0}' isn't an UpperCamelCase identifier.",
correctionMessage:
'Try changing the name to follow the UpperCamelCase style.');
'Try changing the name to follow the UpperCamelCase style.',
hasPublishedDocs: true);

CamelCaseExtensions()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/camel_case_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class CamelCaseTypes 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.');
'Try changing the name to follow the UpperCamelCase style.',
hasPublishedDocs: true);

CamelCaseTypes()
: super(
Expand Down
3 changes: 2 additions & 1 deletion pkg/linter/lib/src/rules/cancel_subscriptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class CancelSubscriptions extends LintRule {
static const LintCode code = LintCode(
'cancel_subscriptions', "Uncancelled instance of 'StreamSubscription'.",
correctionMessage: "Try invoking 'cancel' in the function in which the "
"'StreamSubscription' was created.");
"'StreamSubscription' was created.",
hasPublishedDocs: true);

CancelSubscriptions()
: super(
Expand Down
Loading

0 comments on commit 91254e4

Please sign in to comment.