Add a fix when an extension or mixin has a primary constructor
Neither is allowed to have a primary constructor, This adds a fix to remove the primary constructor. Closes https://github.com/dart-lang/sdk/issues/63073 Change-Id: I363d2fa02d18e2a63a2bfc8c64a57256f861195d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/500584 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
00cda4d60f
commit
e1cacdc23a
@@ -26,6 +26,15 @@ class RemoveConstructor extends ResolvedCorrectionProducer {
|
||||
Future<void> compute(ChangeBuilder builder) async {
|
||||
var container = _findContainer();
|
||||
if (container == null) {
|
||||
// If there's no container, then it must be a primary constructor.
|
||||
var primary = _findPrimaryConstructor();
|
||||
if (primary != null) {
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
builder.addDeletion(
|
||||
range.startEnd(primary.leftParen, primary.rightParen),
|
||||
);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,6 +92,40 @@ class RemoveConstructor extends ResolvedCorrectionProducer {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
_PrimaryConstructor? _findPrimaryConstructor() {
|
||||
switch (node) {
|
||||
case ExtensionDeclaration extension:
|
||||
var leftParen =
|
||||
extension.typeParameters?.endToken.next ?? extension.name?.next;
|
||||
var rightParen = extension.onClause?.onKeyword.previous;
|
||||
if (leftParen != null &&
|
||||
leftParen.type == TokenType.OPEN_PAREN &&
|
||||
rightParen != null &&
|
||||
rightParen.type == TokenType.CLOSE_PAREN) {
|
||||
return _PrimaryConstructor(
|
||||
leftParen: leftParen,
|
||||
rightParen: rightParen,
|
||||
);
|
||||
}
|
||||
case MixinDeclaration mixin:
|
||||
var leftParen = mixin.typeParameters?.endToken.next ?? mixin.name.next;
|
||||
var rightParen =
|
||||
mixin.onClause?.onKeyword.previous ??
|
||||
mixin.implementsClause?.implementsKeyword.previous ??
|
||||
mixin.body.beginToken.previous;
|
||||
if (leftParen != null &&
|
||||
leftParen.type == TokenType.OPEN_PAREN &&
|
||||
rightParen != null &&
|
||||
rightParen.type == TokenType.CLOSE_PAREN) {
|
||||
return _PrimaryConstructor(
|
||||
leftParen: leftParen,
|
||||
rightParen: rightParen,
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class _Container {
|
||||
@@ -91,3 +134,10 @@ class _Container {
|
||||
|
||||
_Container({required this.leftBracket, required this.members});
|
||||
}
|
||||
|
||||
class _PrimaryConstructor {
|
||||
final Token leftParen;
|
||||
final Token rightParen;
|
||||
|
||||
_PrimaryConstructor({required this.leftParen, required this.rightParen});
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ extension_override_with_cascade:
|
||||
extension_override_without_access:
|
||||
status: noFix
|
||||
extension_primary_constructor:
|
||||
status: needsEvaluation
|
||||
status: hasFix
|
||||
extension_type_constructor_with_super_formal_parameter:
|
||||
status: needsFix
|
||||
notes: |-
|
||||
@@ -1141,7 +1141,7 @@ mixin_of_type_alias_expands_to_type_parameter:
|
||||
mixin_on_type_alias_expands_to_type_parameter:
|
||||
status: noFix
|
||||
mixin_primary_constructor:
|
||||
status: needsEvaluation
|
||||
status: hasFix
|
||||
mixin_subtype_of_base_is_not_base:
|
||||
status: hasFix
|
||||
mixin_subtype_of_final_is_not_base:
|
||||
|
||||
@@ -572,6 +572,7 @@ final _builtInNonLintGenerators = <DiagnosticCode, List<ProducerGenerator>>{
|
||||
diag.extensionTypeDeclaresInstanceField: [ConvertIntoGetter.new],
|
||||
diag.extensionOverrideAccessToStaticMember: [ReplaceWithExtensionName.new],
|
||||
diag.extensionOverrideWithCascade: [ReplaceCascadeWithDot.new],
|
||||
diag.extensionPrimaryConstructor: [RemoveConstructor.new],
|
||||
diag.extensionTypeWithAbstractMember: [ConvertIntoBlockBody.missingBody],
|
||||
diag.extraPositionalArguments: [CreateConstructor.new],
|
||||
diag.extraPositionalArgumentsCouldBeNamed: [
|
||||
@@ -659,6 +660,7 @@ final _builtInNonLintGenerators = <DiagnosticCode, List<ProducerGenerator>>{
|
||||
diag.missingRequiredArgument: [AddMissingRequiredArgument.new],
|
||||
diag.mixinApplicationNotImplementedInterface: [ExtendClassForMixin.new],
|
||||
diag.mixinClassDeclarationExtendsNotObject: [RemoveExtendsClause.new],
|
||||
diag.mixinPrimaryConstructor: [RemoveConstructor.new],
|
||||
diag.mixinSubtypeOfBaseIsNotBase: [AddClassModifier.baseModifier],
|
||||
diag.mixinSubtypeOfFinalIsNotBase: [AddClassModifier.baseModifier],
|
||||
diag.mixinOfDisallowedClass: [RemoveNameFromDeclarationClause.new],
|
||||
|
||||
@@ -103,6 +103,24 @@ extension E on int {
|
||||
await assertHasFix('''
|
||||
extension E on int {
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_primaryConstructor() async {
|
||||
await resolveTestCode('''
|
||||
extension E() on int;
|
||||
''');
|
||||
await assertHasFix('''
|
||||
extension E on int;
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_primaryConstructor_withTypeParameters() async {
|
||||
await resolveTestCode('''
|
||||
extension E<T>() on int;
|
||||
''');
|
||||
await assertHasFix('''
|
||||
extension E<T> on int;
|
||||
''');
|
||||
}
|
||||
}
|
||||
@@ -195,6 +213,51 @@ mixin M {
|
||||
await assertHasFix('''
|
||||
mixin M {
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_primaryConstructor_emptyBody() async {
|
||||
await resolveTestCode('''
|
||||
mixin M() {}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
mixin M {}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_primaryConstructor_implements() async {
|
||||
await resolveTestCode('''
|
||||
mixin M() implements Object {}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
mixin M implements Object {}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_primaryConstructor_semicolon() async {
|
||||
await resolveTestCode('''
|
||||
mixin M();
|
||||
''');
|
||||
await assertHasFix('''
|
||||
mixin M;
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_primaryConstructor_withOnClause() async {
|
||||
await resolveTestCode('''
|
||||
mixin M() on Object {}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
mixin M on Object {}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_primaryConstructor_withTypeParameters() async {
|
||||
await resolveTestCode('''
|
||||
mixin M<T>() {}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
mixin M<T> {}
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user