Add an unnecessary_primary_constructor_body lint
The lint will fire even when there is a comment in the body, such as
```dart
class C() {
this { /* comment */ }
}
```
I think this is the right behavior because I can't think of any useful
comment that wouldn't be better somewhere else, but let me know if you
disagree.
This doesn't yet have a fix, but it should.
Change-Id: Ia5ffa6b06c75a6a7400ec32a9d22209c08a9c73d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/510401
Reviewed-by: Keerti Parthasarathy <keertip@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
2a3c26806f
commit
9f47e3186d
@@ -2583,6 +2583,10 @@ unnecessary_overrides:
|
||||
status: hasFix
|
||||
unnecessary_parenthesis:
|
||||
status: hasFix
|
||||
unnecessary_primary_constructor_body:
|
||||
status: needsFix
|
||||
notes: |-
|
||||
The fix is to remove the body.
|
||||
unnecessary_raw_strings:
|
||||
status: hasFix
|
||||
unnecessary_statements:
|
||||
|
||||
@@ -3422,6 +3422,16 @@ const LinterLintWithoutArguments unnecessaryParenthesis =
|
||||
expectedTypes: [],
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
const LinterLintWithoutArguments unnecessaryPrimaryConstructorBody =
|
||||
LinterLintWithoutArguments(
|
||||
name: 'unnecessary_primary_constructor_body',
|
||||
problemMessage: "Unnecessary primary constructor body.",
|
||||
correctionMessage: "Try removing the body.",
|
||||
uniqueName: 'unnecessary_primary_constructor_body',
|
||||
expectedTypes: [],
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
const LinterLintWithoutArguments unnecessaryRawStrings =
|
||||
LinterLintWithoutArguments(
|
||||
|
||||
@@ -582,6 +582,9 @@ abstract final class LintNames {
|
||||
|
||||
static const String unnecessary_parenthesis = 'unnecessary_parenthesis';
|
||||
|
||||
static const String unnecessary_primary_constructor_body =
|
||||
'unnecessary_primary_constructor_body';
|
||||
|
||||
static const String unnecessary_raw_strings = 'unnecessary_raw_strings';
|
||||
|
||||
static const String unnecessary_statements = 'unnecessary_statements';
|
||||
|
||||
@@ -230,6 +230,7 @@ import 'rules/unnecessary_null_in_if_null_operators.dart';
|
||||
import 'rules/unnecessary_nullable_for_final_variable_declarations.dart';
|
||||
import 'rules/unnecessary_overrides.dart';
|
||||
import 'rules/unnecessary_parenthesis.dart';
|
||||
import 'rules/unnecessary_primary_constructor_body.dart';
|
||||
import 'rules/unnecessary_raw_strings.dart';
|
||||
import 'rules/unnecessary_statements.dart';
|
||||
import 'rules/unnecessary_string_escapes.dart';
|
||||
@@ -497,6 +498,7 @@ void registerLintRules() {
|
||||
..registerLintRule(UnnecessaryNullableForFinalVariableDeclarations())
|
||||
..registerLintRule(UnnecessaryOverrides())
|
||||
..registerLintRule(UnnecessaryParenthesis())
|
||||
..registerLintRule(UnnecessaryPrimaryConstructorBody())
|
||||
..registerLintRule(UnnecessaryRawStrings())
|
||||
..registerLintRule(UnnecessaryStatements())
|
||||
..registerLintRule(UnnecessaryStringEscapes())
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2026, 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/analysis_rule/analysis_rule.dart';
|
||||
import 'package:analyzer/analysis_rule/rule_context.dart';
|
||||
import 'package:analyzer/analysis_rule/rule_visitor_registry.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/visitor.dart';
|
||||
import 'package:analyzer/dart/element/type_system.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
|
||||
import '../analyzer.dart';
|
||||
import '../diagnostic.dart' as diag;
|
||||
|
||||
const _desc = r'Unnecessary primary constructor bodies can be removed.';
|
||||
|
||||
class UnnecessaryPrimaryConstructorBody extends AnalysisRule {
|
||||
new()
|
||||
: super(
|
||||
name: LintNames.unnecessary_primary_constructor_body,
|
||||
description: _desc,
|
||||
);
|
||||
|
||||
@override
|
||||
DiagnosticCode get diagnosticCode => diag.unnecessaryPrimaryConstructorBody;
|
||||
|
||||
@override
|
||||
void registerNodeProcessors(
|
||||
RuleVisitorRegistry registry,
|
||||
RuleContext context,
|
||||
) {
|
||||
var visitor = _Visitor(this, context.typeSystem);
|
||||
registry.addPrimaryConstructorBody(this, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
class _Visitor extends SimpleAstVisitor<void> {
|
||||
final AnalysisRule rule;
|
||||
final TypeSystem typeSystem;
|
||||
|
||||
new(this.rule, this.typeSystem);
|
||||
|
||||
@override
|
||||
void visitPrimaryConstructorBody(PrimaryConstructorBody node) {
|
||||
var body = node.body;
|
||||
if (node.metadata.isNotEmpty) return;
|
||||
if (node.documentationComment != null) return;
|
||||
if (node.initializers.isNotEmpty) return;
|
||||
|
||||
if (body is EmptyFunctionBody) {
|
||||
rule.reportAtToken(node.thisKeyword);
|
||||
} else if (body is BlockFunctionBody && body.block.statements.isEmpty) {
|
||||
rule.reportAtToken(node.thisKeyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15380,6 +15380,29 @@ LinterLintCode:
|
||||
* logical expressions - parentheses can improve the readability of the implicit
|
||||
grouping defined by precedence. For example, the expression
|
||||
`(a && b) || c && d`.
|
||||
unnecessaryPrimaryConstructorBody:
|
||||
type: lint
|
||||
parameters: none
|
||||
problemMessage: "Unnecessary primary constructor body."
|
||||
correctionMessage: "Try removing the body."
|
||||
state:
|
||||
experimental: "3.13"
|
||||
categories: [brevity, style]
|
||||
hasPublishedDocs: false
|
||||
deprecatedDetails: |-
|
||||
Don't include an empty primary constructor body.
|
||||
|
||||
**BAD:**
|
||||
```dart
|
||||
class C() {
|
||||
this;
|
||||
}
|
||||
```
|
||||
|
||||
**GOOD:**
|
||||
```dart
|
||||
class C();
|
||||
```
|
||||
unnecessaryRawStrings:
|
||||
type: lint
|
||||
parameters: none
|
||||
|
||||
@@ -295,6 +295,8 @@ import 'unnecessary_nullable_for_final_variable_declarations_test.dart'
|
||||
as unnecessary_nullable_for_final_variable_declarations;
|
||||
import 'unnecessary_overrides_test.dart' as unnecessary_overrides;
|
||||
import 'unnecessary_parenthesis_test.dart' as unnecessary_parenthesis;
|
||||
import 'unnecessary_primary_constructor_body_test.dart'
|
||||
as unnecessary_primary_constructor_body;
|
||||
import 'unnecessary_raw_strings_test.dart' as unnecessary_raw_strings;
|
||||
import 'unnecessary_statements_test.dart' as unnecessary_statements;
|
||||
import 'unnecessary_string_escapes_test.dart' as unnecessary_string_escapes;
|
||||
@@ -562,6 +564,7 @@ void main() {
|
||||
unnecessary_nullable_for_final_variable_declarations.main();
|
||||
unnecessary_overrides.main();
|
||||
unnecessary_parenthesis.main();
|
||||
unnecessary_primary_constructor_body.main();
|
||||
unnecessary_raw_strings.main();
|
||||
unnecessary_statements.main();
|
||||
unnecessary_string_escapes.main();
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2026, 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:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../rule_test_support.dart';
|
||||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(UnnecessaryPrimaryConstructorBodyTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class UnnecessaryPrimaryConstructorBodyTest extends LintRuleTest {
|
||||
@override
|
||||
String get lintRule => LintNames.unnecessary_primary_constructor_body;
|
||||
|
||||
test_emptyBody_block() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
class C() {
|
||||
[!this!] {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_emptyBody_semicolon() async {
|
||||
await assertDiagnosticsFromMarkdown(r'''
|
||||
class C() {
|
||||
[!this!];
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasDocComment() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C() {
|
||||
/// comment
|
||||
this;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasInitializer() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C(int i) {
|
||||
this : assert(i >= 0);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasMetadata() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C() {
|
||||
@deprecated
|
||||
this;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasNonEmptyBody() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C(int i) {
|
||||
this {
|
||||
print(i);
|
||||
}
|
||||
}
|
||||
''');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user