diff --git a/pkg/linter/lib/src/rules/prefer_const_constructors.dart b/pkg/linter/lib/src/rules/prefer_const_constructors.dart index 054a79f4b44..7f2e099e432 100644 --- a/pkg/linter/lib/src/rules/prefer_const_constructors.dart +++ b/pkg/linter/lib/src/rules/prefer_const_constructors.dart @@ -24,6 +24,7 @@ class PreferConstConstructors extends LintRule { @override void registerNodeProcessors(NodeLintRegistry registry, RuleContext context) { var visitor = _Visitor(this); + registry.addDotShorthandConstructorInvocation(this, visitor); registry.addInstanceCreationExpression(this, visitor); } } @@ -33,6 +34,30 @@ class _Visitor extends SimpleAstVisitor { _Visitor(this.rule); + @override + void visitDotShorthandConstructorInvocation( + DotShorthandConstructorInvocation node, + ) { + if (node.isConst) return; + + var element = node.constructorName.element; + if (element is! ConstructorElement) return; + if (!element.isConst) return; + + // Handled by an analyzer warning. + if (element.metadata.hasLiteral) return; + + var enclosingElement = element.enclosingElement; + if (enclosingElement is ClassElement && enclosingElement.isDartCoreObject) { + // Skip lint for `new Object()`, because it can be used for ID creation. + return; + } + + if (node.canBeConst) { + rule.reportAtNode(node); + } + } + @override void visitInstanceCreationExpression(InstanceCreationExpression node) { if (node.isConst) return; diff --git a/pkg/linter/test/rules/prefer_const_constructors_test.dart b/pkg/linter/test/rules/prefer_const_constructors_test.dart index eafe8843ad2..4f0c654cde0 100644 --- a/pkg/linter/test/rules/prefer_const_constructors_test.dart +++ b/pkg/linter/test/rules/prefer_const_constructors_test.dart @@ -74,6 +74,18 @@ var a = A({}); ); } + test_canBeConst_dotShorthand() async { + await assertDiagnostics( + r''' +class A { + const A(); +} +A a = .new(); +''', + [lint(31, 6)], + ); + } + test_canBeConst_explicitTypeArgument_dynamic() async { await assertDiagnostics( r''' @@ -275,6 +287,15 @@ var a = A(); '''); } + test_cannotBeConst_notConstConstructor_dotShorthand() async { + await assertNoDiagnostics(r''' +class A { + A(); +} +A a = .new(); +'''); + } + test_cannotBeConst_stringLiteralArgument_withInterpolation() async { await assertNoDiagnostics(r''' class A { @@ -363,6 +384,28 @@ K k() { ); } + test_extraPositionalArgument_dotShorthands() async { + await assertDiagnostics( + r''' +import 'package:meta/meta.dart'; + +class K { + @literal + const K(); +} + +K k() { + K kk = .new(); + return kk; +} +''', + [ + // No lint + error(WarningCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR, 88, 6), + ], + ); + } + test_isConst_intLiteralArgument() async { await assertNoDiagnostics(r''' class A { @@ -386,6 +429,12 @@ var a = const A(); test_objectConstructorCall() async { await assertNoDiagnostics(r''' var x = Object(); +'''); + } + + test_objectConstructorCall_dotShorthand() async { + await assertNoDiagnostics(r''' +Object x = .new(); '''); } }