Augment. Report augmentationOfMixinApplicationClass.
Change-Id: I2649f4eb96fc232727fafa16129799ef3f207e20 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/494340 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Paul Berry <paulberry@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
78412eaeb8
commit
18ab2664ca
@@ -241,6 +241,8 @@ augmentation_modifier_missing:
|
||||
status: needsFix
|
||||
augmentation_of_different_declaration_kind:
|
||||
status: noFix
|
||||
augmentation_of_mixin_application_class:
|
||||
status: needsEvaluation
|
||||
augmentation_type_parameter_bound:
|
||||
status: noFix
|
||||
augmentation_type_parameter_count:
|
||||
|
||||
@@ -943,6 +943,19 @@ augmentationOfDifferentDeclarationKind = DiagnosticWithArguments(
|
||||
expectedTypes: [ExpectedType.string, ExpectedType.string],
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
const DiagnosticWithoutArguments augmentationOfMixinApplicationClass =
|
||||
DiagnosticWithoutArgumentsImpl(
|
||||
name: 'augmentation_of_mixin_application_class',
|
||||
problemMessage: "Mixin application classes can't be augmented.",
|
||||
correctionMessage:
|
||||
"Try removing the 'augment' keyword, or making the target a normal "
|
||||
"class.",
|
||||
type: DiagnosticType.COMPILE_TIME_ERROR,
|
||||
uniqueName: 'augmentation_of_mixin_application_class',
|
||||
expectedTypes: [],
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
const DiagnosticWithoutArguments augmentationTypeParameterBound =
|
||||
DiagnosticWithoutArgumentsImpl(
|
||||
|
||||
@@ -73,6 +73,7 @@ const List<DiagnosticCode> diagnosticCodeValues = [
|
||||
diag.augmentationModifierExtra,
|
||||
diag.augmentationModifierMissing,
|
||||
diag.augmentationOfDifferentDeclarationKind,
|
||||
diag.augmentationOfMixinApplicationClass,
|
||||
diag.augmentationTypeParameterBound,
|
||||
diag.augmentationTypeParameterCount,
|
||||
diag.augmentationTypeParameterName,
|
||||
|
||||
@@ -2018,33 +2018,38 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
||||
if (augmentKeyword != null) {
|
||||
if (fragment.previousFragment == null) {
|
||||
var element = fragment.element;
|
||||
if (element.previousFragmentOfDifferentKind case var previous?) {
|
||||
diagnosticReporter.report(
|
||||
diag.augmentationOfDifferentDeclarationKind
|
||||
.withArguments(
|
||||
declarationKind: previous.element.kind.displayName,
|
||||
augmentationKind: element.kind.displayName,
|
||||
)
|
||||
.withContextMessages([
|
||||
if (previous case FragmentImpl(
|
||||
libraryFragment: var libraryFragment?,
|
||||
name: var name?,
|
||||
nameOffset: var nameOffset?,
|
||||
))
|
||||
DiagnosticMessageImpl(
|
||||
filePath: libraryFragment.source.fullName,
|
||||
message: "The declaration being augmented.",
|
||||
offset: nameOffset,
|
||||
length: name.length,
|
||||
url: null,
|
||||
var previousFragmentOfDifferentKind =
|
||||
element.previousFragmentOfDifferentKind;
|
||||
switch (previousFragmentOfDifferentKind) {
|
||||
case ClassFragmentImpl(isMixinApplication: true):
|
||||
diagnosticReporter.report(
|
||||
diag.augmentationOfMixinApplicationClass
|
||||
.withContextMessages([
|
||||
?previousFragmentOfDifferentKind.contextMessageAt(
|
||||
"The declaration being augmented.",
|
||||
),
|
||||
])
|
||||
.at(augmentKeyword),
|
||||
);
|
||||
} else {
|
||||
diagnosticReporter.report(
|
||||
diag.augmentationWithoutDeclaration.at(augmentKeyword),
|
||||
);
|
||||
])
|
||||
.at(augmentKeyword),
|
||||
);
|
||||
case FragmentImpl previousFragment:
|
||||
var previousElement = previousFragment.element;
|
||||
diagnosticReporter.report(
|
||||
diag.augmentationOfDifferentDeclarationKind
|
||||
.withArguments(
|
||||
declarationKind: previousElement.kind.displayName,
|
||||
augmentationKind: element.kind.displayName,
|
||||
)
|
||||
.withContextMessages([
|
||||
?previousFragment.contextMessageAt(
|
||||
"The declaration being augmented.",
|
||||
),
|
||||
])
|
||||
.at(augmentKeyword),
|
||||
);
|
||||
case null:
|
||||
diagnosticReporter.report(
|
||||
diag.augmentationWithoutDeclaration.at(augmentKeyword),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,9 @@ class ElementBuilder {
|
||||
) {
|
||||
libraryFragment.addClass(fragment);
|
||||
|
||||
if (fragment.isAugmentation && lastFragment is ClassFragmentImpl) {
|
||||
if (fragment.isAugmentation &&
|
||||
lastFragment is ClassFragmentImpl &&
|
||||
!lastFragment.isMixinApplication) {
|
||||
lastFragment.addFragment(fragment);
|
||||
|
||||
_linkTypeParameters(
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/member.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/diagnostic/diagnostic_message.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
class MockLibraryImportElement implements Element {
|
||||
@@ -260,6 +261,24 @@ extension FormalParameterElementImplExtension on FormalParameterElementImpl {
|
||||
}
|
||||
}
|
||||
|
||||
extension FragmentImplExtension on FragmentImpl {
|
||||
DiagnosticMessageImpl? contextMessageAt(String message) {
|
||||
var libraryFragment = this.libraryFragment;
|
||||
var nameOffset = this.nameOffset;
|
||||
var name = this.name;
|
||||
if (libraryFragment != null && nameOffset != null && name != null) {
|
||||
return DiagnosticMessageImpl(
|
||||
filePath: libraryFragment.source.fullName,
|
||||
message: message,
|
||||
offset: nameOffset,
|
||||
length: name.length,
|
||||
url: null,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
extension GetterElementImplExtension on GetterElementImpl {
|
||||
PropertyAccessorFragmentImpl get asElement {
|
||||
return lastFragment;
|
||||
|
||||
@@ -1869,6 +1869,13 @@ CompileTimeErrorCode:
|
||||
problemMessage: The declaration being augmented doesn't exist.
|
||||
correctionMessage: Try changing the augmentation to match an existing declaration.
|
||||
hasPublishedDocs: false
|
||||
augmentationOfMixinApplicationClass:
|
||||
type: compileTimeError
|
||||
parameters: none
|
||||
experiment: augmentations
|
||||
problemMessage: "Mixin application classes can't be augmented."
|
||||
correctionMessage: Try removing the 'augment' keyword, or making the target a normal class.
|
||||
hasPublishedDocs: false
|
||||
augmentedExpressionIsNotSetter:
|
||||
type: compileTimeError
|
||||
parameters: none
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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/src/diagnostic/diagnostic.dart' as diag;
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(AugmentationOfMixinApplicationClassTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class AugmentationOfMixinApplicationClassTest extends PubPackageResolutionTest {
|
||||
test_class() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {}
|
||||
mixin M {}
|
||||
class C = A with M;
|
||||
augment class C {}
|
||||
''',
|
||||
[
|
||||
error(
|
||||
diag.augmentationOfMixinApplicationClass,
|
||||
42,
|
||||
7,
|
||||
contextMessages: [message(testFile, 28, 1)],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,8 @@ import 'augmentation_modifier_missing_test.dart'
|
||||
as augmentation_modifier_missing;
|
||||
import 'augmentation_of_different_declaration_kind_test.dart'
|
||||
as augmentation_of_different_declaration_kind;
|
||||
import 'augmentation_of_mixin_application_class_test.dart'
|
||||
as augmentation_of_mixin_application_class;
|
||||
import 'augmentation_type_parameter_bound_test.dart'
|
||||
as augmentation_type_parameter_bound;
|
||||
import 'augmentation_type_parameter_count_test.dart'
|
||||
@@ -984,6 +986,7 @@ main() {
|
||||
augmentation_modifier_extra.main();
|
||||
augmentation_modifier_missing.main();
|
||||
augmentation_of_different_declaration_kind.main();
|
||||
augmentation_of_mixin_application_class.main();
|
||||
augmentation_type_parameter_bound.main();
|
||||
augmentation_type_parameter_count.main();
|
||||
augmentation_type_parameter_name.main();
|
||||
|
||||
@@ -26038,6 +26038,70 @@ library
|
||||
''');
|
||||
}
|
||||
|
||||
test_augmentation_mixinApplication() async {
|
||||
var library = await buildLibrary(r'''
|
||||
mixin M {}
|
||||
class C = Object with M;
|
||||
augment class C {}
|
||||
''');
|
||||
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
reference: <testLibrary>
|
||||
fragments
|
||||
#F0 <testLibraryFragment>
|
||||
element: <testLibrary>
|
||||
classes
|
||||
#F1 isMixinApplication class C (nameOffset:17) (firstTokenOffset:11) (offset:17)
|
||||
element: <testLibrary>::@class::C::@def::0
|
||||
constructors
|
||||
#F2 isConst isOriginMixinApplication new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:17)
|
||||
element: <testLibrary>::@class::C::@def::0::@constructor::new
|
||||
typeName: C
|
||||
#F3 isAugmentation class C (nameOffset:50) (firstTokenOffset:36) (offset:50)
|
||||
element: <testLibrary>::@class::C::@def::1
|
||||
constructors
|
||||
#F4 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:50)
|
||||
element: <testLibrary>::@class::C::@def::1::@constructor::new
|
||||
typeName: C
|
||||
mixins
|
||||
#F5 mixin M (nameOffset:6) (firstTokenOffset:0) (offset:6)
|
||||
element: <testLibrary>::@mixin::M
|
||||
classes
|
||||
isMixinApplication isSimplyBounded class C
|
||||
reference: <testLibrary>::@class::C::@def::0
|
||||
firstFragment: #F1
|
||||
supertype: Object
|
||||
mixins
|
||||
M
|
||||
constructors
|
||||
isConst isOriginMixinApplication new
|
||||
reference: <testLibrary>::@class::C::@def::0::@constructor::new
|
||||
firstFragment: #F2
|
||||
constantInitializers
|
||||
SuperConstructorInvocation
|
||||
superKeyword: super @0
|
||||
argumentList: ArgumentList
|
||||
leftParenthesis: ( @0
|
||||
rightParenthesis: ) @0
|
||||
element: dart:core::@class::Object::@constructor::new
|
||||
isSimplyBounded class C
|
||||
reference: <testLibrary>::@class::C::@def::1
|
||||
firstFragment: #F3
|
||||
previousFragmentOfDifferentKind: #F1
|
||||
constructors
|
||||
isOriginImplicitDefault new
|
||||
reference: <testLibrary>::@class::C::@def::1::@constructor::new
|
||||
firstFragment: #F4
|
||||
mixins
|
||||
isSimplyBounded mixin M
|
||||
reference: <testLibrary>::@mixin::M
|
||||
firstFragment: #F5
|
||||
superclassConstraints
|
||||
Object
|
||||
''');
|
||||
}
|
||||
|
||||
test_augmentationTarget() async {
|
||||
newFile('$testPackageLibPath/a1.dart', r'''
|
||||
part of 'test.dart';
|
||||
|
||||
Reference in New Issue
Block a user