Augment. Report augmentationOfDifferentDeclarationKind.

Keep track of the most recent same-named fragment even when it has a
different declaration kind. This lets augmentation validation
distinguish between a missing target and a target whose kind does not
match the augmentation.

Store this information on elements, serialize it through summaries, and
use it during error verification. When an augmentation finds a previous
declaration with the same name but a different kind, report
`augmentationOfDifferentDeclarationKind` and attach a context message
that points to the original declaration instead of falling back to
`augmentationWithoutDeclaration`.

This improves diagnostics for both top-level and member declarations,
including combinations such as constructors vs fields, methods vs
accessors, and functions vs variables.

Change-Id: Ic794c437fa160bb29d25f90559b544a7282ca697
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/494301
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov
2026-04-20 09:33:03 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 47a4c9a0ae
commit 9e690bdd06
16 changed files with 5492 additions and 522 deletions
@@ -108,7 +108,7 @@ testFineAfterLibraryAnalyzerHook;
// TODO(scheglov): Clean up the list of implicitly analyzed files.
class AnalysisDriver {
/// The version of data format, should be incremented on every format change.
static const int DATA_VERSION = 624;
static const int DATA_VERSION = 626;
/// The number of exception contexts allowed to write. Once this field is
/// zero, we stop writing any new exception contexts in this process.
@@ -1986,6 +1986,12 @@ abstract class ElementImpl implements Element {
@trackedIncludedInId
final int id = FragmentImpl._NEXT_ID++;
/// The previous fragment with the same name in the library, but of a
/// different kind. Used for error reporting when an augmentation does not
/// match the kind of the declaration it augments.
@trackedIncludedInId
FragmentImpl? previousFragmentOfDifferentKind;
/// The flags associated with this element.
EnumSet<_ElementStorageFlag> _flags = EnumSet.empty();
@@ -762,6 +762,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
covariant EnumConstantDeclarationImpl node,
) {
_checkEnumConstantSameAsEnclosing(node);
_checkAugmentationWithoutDeclaration(
node.augmentKeyword,
node.declaredFragment!,
);
_requiredParametersVerifier.visitEnumConstantDeclaration(node);
_typeArgumentsVerifier.checkEnumConstantDeclaration(node);
super.visitEnumConstantDeclaration(node);
@@ -1871,7 +1875,9 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
}
@override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
void visitTopLevelVariableDeclaration(
covariant TopLevelVariableDeclarationImpl node,
) {
var variableList = node.variables;
if (node.augmentKeyword case var augmentKeyword?) {
@@ -2007,13 +2013,39 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
void _checkAugmentationWithoutDeclaration(
Token? augmentKeyword,
Fragment fragment,
FragmentImpl fragment,
) {
if (augmentKeyword != null) {
if (fragment.previousFragment == null) {
diagnosticReporter.report(
diag.augmentationWithoutDeclaration.at(augmentKeyword),
);
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,
),
])
.at(augmentKeyword),
);
} else {
diagnosticReporter.report(
diag.augmentationWithoutDeclaration.at(augmentKeyword),
);
}
}
}
}
@@ -261,6 +261,7 @@ class LibraryReader {
var fragments = _readFragmentsById<ClassFragmentImpl>();
var element = ClassElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.hasNonFinalField = _reader.readBool();
@@ -344,6 +345,7 @@ class LibraryReader {
firstFragment: fragments.first,
);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.deferReadResolution(
@@ -457,6 +459,7 @@ class LibraryReader {
var fragments = _readFragmentsById<EnumFragmentImpl>();
var element = EnumElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.hasNonFinalField = _reader.readBool();
@@ -552,6 +555,7 @@ class LibraryReader {
var fragments = _readFragmentsById<ExtensionFragmentImpl>();
var element = ExtensionElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
_lazyRead((offset) {
@@ -618,6 +622,7 @@ class LibraryReader {
var fragments = _readFragmentsById<ExtensionTypeFragmentImpl>();
var element = ExtensionTypeElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.hasRepresentationSelfReference = _reader.readBool();
@@ -698,6 +703,7 @@ class LibraryReader {
firstFragment: fragments.first,
);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.typeInferenceError = _readTopLevelInferenceError();
@@ -834,6 +840,7 @@ class LibraryReader {
var fragments = _readFragmentsById<GetterFragmentImpl>();
var element = GetterElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.deferReadResolution(
@@ -1013,6 +1020,7 @@ class LibraryReader {
firstFragment: fragments.first,
);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.typeInferenceError = _readTopLevelInferenceError();
@@ -1069,6 +1077,7 @@ class LibraryReader {
var fragments = _readFragmentsById<MixinFragmentImpl>();
var element = MixinElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.hasNonFinalField = _reader.readBool();
@@ -1150,6 +1159,10 @@ class LibraryReader {
}
}
FragmentImpl? _readOptionalFragmentById() {
return _reader.readOptionalObject(_readFragmentById);
}
/// Read the reference of a non-local element.
Reference? _readOptionalReference() {
return _reader.readOptionalObject(() => _readReference());
@@ -1174,6 +1187,7 @@ class LibraryReader {
var fragments = _readFragmentsById<SetterFragmentImpl>();
var element = SetterElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.deferReadResolution(
@@ -1251,6 +1265,7 @@ class LibraryReader {
var fragments = _readFragmentsById<TopLevelFunctionFragmentImpl>();
var element = TopLevelFunctionElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.deferReadResolution(
@@ -1304,6 +1319,7 @@ class LibraryReader {
var fragments = _readFragmentsById<TopLevelVariableFragmentImpl>();
var element = TopLevelVariableElementImpl(reference, fragments.first);
element.linkFragments(fragments);
element.previousFragmentOfDifferentKind = _readOptionalFragmentById();
element.readFlags(_reader);
element.typeInferenceError = _readTopLevelInferenceError();
@@ -140,6 +140,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_sink.writeBool(element.hasNonFinalField);
@@ -192,6 +193,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
assert(element.typeParameters.isEmpty);
@@ -262,6 +264,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_sink.writeBool(element.hasNonFinalField);
@@ -329,6 +332,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_writeForLazyRead(() {
@@ -370,6 +374,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
// TODO(fshcheglov): Put these separate flags into modifiers
@@ -425,6 +430,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_sink._writeTopLevelInferenceError(element.typeInferenceError);
@@ -528,6 +534,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
assert(element.typeParameters.isEmpty);
@@ -618,6 +625,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_sink._writeTopLevelInferenceError(element.typeInferenceError);
@@ -648,6 +656,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_sink.writeBool(element.hasNonFinalField);
@@ -707,6 +716,10 @@ class BundleWriter {
}
}
void _writeOptionalFragmentId(FragmentImpl? fragment) {
_sink.writeOptionalObject(fragment, _writeFragmentId);
}
void _writeOptionalReference(Reference? reference) {
_sink.writeOptionalObject(reference, _writeReference);
}
@@ -740,6 +753,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
assert(element.typeParameters.isEmpty);
@@ -775,6 +789,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_writeElementResolution(() {
@@ -805,6 +820,7 @@ class BundleWriter {
_sink.writeList(elements, (element) {
_writeReference(element.reference);
_writeFragments(element.fragments);
_writeOptionalFragmentId(element.previousFragmentOfDifferentKind);
element.writeFlags(_sink);
_sink._writeTopLevelInferenceError(element.typeInferenceError);
_writeElementResolution(() {
@@ -64,8 +64,20 @@ class ElementBuilder {
for (var instanceEntry in elementChildFragments.entries) {
var instanceElement = instanceEntry.key;
var lastFragments = <String?, FragmentImpl>{};
var lastInstanceFragments = <String?, FragmentImpl>{};
var lastStaticFragments = <String?, FragmentImpl>{};
for (var fragment in instanceEntry.value) {
var isInStaticNamespace = switch (fragment) {
ConstructorFragmentImpl() => true,
FieldFragmentImpl(:var isStatic) => isStatic,
GetterFragmentImpl(:var isStatic) => isStatic,
SetterFragmentImpl(:var isStatic) => isStatic,
MethodFragmentImpl(:var isStatic) => isStatic,
_ => false,
};
var lastFragments = isInStaticNamespace
? lastStaticFragments
: lastInstanceFragments;
var lastFragment = lastFragments[fragment.name];
switch (fragment) {
case FieldFragmentImpl():
@@ -211,6 +223,10 @@ class ElementBuilder {
TypeParameterElementImpl(firstFragment: typeParameter);
}
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addClass(element);
libraryBuilder.declare(element, element.reference);
}
@@ -243,6 +259,10 @@ class ElementBuilder {
TypeParameterElementImpl(firstFragment: typeParameter);
}
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addEnum(element);
libraryBuilder.declare(element, element.reference);
}
@@ -275,6 +295,10 @@ class ElementBuilder {
TypeParameterElementImpl(firstFragment: typeParameter);
}
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addExtension(element);
libraryBuilder.declare(element, element.reference);
}
@@ -307,6 +331,10 @@ class ElementBuilder {
TypeParameterElementImpl(firstFragment: typeParameter);
}
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addExtensionType(element);
libraryBuilder.declare(element, element.reference);
}
@@ -346,6 +374,10 @@ class ElementBuilder {
firstFragment: fragment,
);
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
interfaceElement.addConstructor(element);
}
@@ -389,6 +421,9 @@ class ElementBuilder {
),
firstFragment: fieldFragment,
);
if (fieldFragment.isAugmentation && lastFragment != null) {
fieldElement.previousFragmentOfDifferentKind = lastFragment;
}
instanceElement.addField(fieldElement);
{
@@ -462,6 +497,9 @@ class ElementBuilder {
_addInstanceReference(instanceElement, '@getter', getterFragment.name),
getterFragment,
);
if (getterFragment.isAugmentation && lastFragment != null) {
getterElement.previousFragmentOfDifferentKind = lastFragment;
}
instanceElement.addGetter(getterElement);
// `class Enum {}` in `dart:core` declares `int get index` as abstract.
@@ -533,17 +571,21 @@ class ElementBuilder {
TypeParameterElementImpl(firstFragment: typeParameter);
}
instanceElement.addMethod(
MethodElementImpl(
name: fragment.name,
reference: _addInstanceReference(
instanceElement,
'@method',
fragment.lookupName,
),
firstFragment: fragment,
var element = MethodElementImpl(
name: fragment.name,
reference: _addInstanceReference(
instanceElement,
'@method',
fragment.lookupName,
),
firstFragment: fragment,
);
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
instanceElement.addMethod(element);
}
void _handleInstanceSetterFragment(
@@ -570,6 +612,9 @@ class ElementBuilder {
_addInstanceReference(instanceElement, '@setter', setterFragment.name),
setterFragment,
);
if (setterFragment.isAugmentation && lastFragment != null) {
setterElement.previousFragmentOfDifferentKind = lastFragment;
}
instanceElement.addSetter(setterElement);
// If `setter` is already set, this is a compile-time error.
@@ -628,6 +673,10 @@ class ElementBuilder {
TypeParameterElementImpl(firstFragment: typeParameter);
}
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addMixin(element);
libraryBuilder.declare(element, element.reference);
}
@@ -665,6 +714,10 @@ class ElementBuilder {
TypeParameterElementImpl(firstFragment: typeParameter);
}
if (fragment.isAugmentation && lastFragment != null) {
element.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addTopLevelFunction(element);
libraryBuilder.declare(element, element.reference);
}
@@ -690,6 +743,9 @@ class ElementBuilder {
_addTopReference('@getter', getterFragment.name),
getterFragment,
);
if (getterFragment.isAugmentation && lastFragment != null) {
getterElement.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addGetter(getterElement);
libraryBuilder.declare(getterElement, getterElement.reference);
@@ -740,6 +796,9 @@ class ElementBuilder {
_addTopReference('@setter', setterFragment.name),
setterFragment,
);
if (setterFragment.isAugmentation && lastFragment != null) {
setterElement.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addSetter(setterElement);
libraryBuilder.declare(setterElement, setterElement.reference);
@@ -787,6 +846,9 @@ class ElementBuilder {
_addTopReference('@topLevelVariable', variableFragment.name),
variableFragment,
);
if (variableFragment.isAugmentation && lastFragment != null) {
variableElement.previousFragmentOfDifferentKind = lastFragment;
}
libraryElement.addTopLevelVariable(variableElement);
{
File diff suppressed because it is too large Load Diff
@@ -24,6 +24,14 @@ augment class A {}
);
}
test_class_augments_class() async {
await assertNoErrorsInCode(r'''
class A {}
augment class A {}
''');
}
test_class_constructor() async {
await assertErrorsInCode(
r'''
@@ -37,7 +45,37 @@ augment class A {
);
}
test_class_field() async {
test_class_constructor_augments_instanceField() async {
await assertErrorsInCode(
r'''
class A {
int foo = 0;
}
augment class A {
augment A.foo();
}
''',
[error(diag.augmentationWithoutDeclaration, 48, 7)],
);
}
test_class_constructor_augments_instanceMethod() async {
await assertErrorsInCode(
r'''
class A {
void foo() {}
}
augment class A {
augment A.foo();
}
''',
[error(diag.augmentationWithoutDeclaration, 49, 7)],
);
}
test_class_instanceField() async {
await assertErrorsInCode(
r'''
class A {}
@@ -50,20 +88,22 @@ augment class A {
);
}
test_class_field_static() async {
test_class_instanceField_augments_constructor() async {
await assertErrorsInCode(
r'''
class A {}
class A {
A.foo();
}
augment class A {
augment static int foo = 0;
augment int foo = 0;
}
''',
[error(diag.augmentationWithoutDeclaration, 32, 7)],
[error(diag.augmentationWithoutDeclaration, 44, 7)],
);
}
test_class_field_valid() async {
test_class_instanceField_augments_instanceField() async {
await assertNoErrorsInCode(r'''
class A {
int foo = 0;
@@ -75,7 +115,48 @@ augment class A {
''');
}
test_class_getter() async {
test_class_instanceField_augments_staticField() async {
await assertErrorsInCode(
r'''
class A {
static int foo = 0;
}
augment class A {
augment int foo = 0;
}
''',
[
error(diag.conflictingStaticAndInstance, 23, 3),
error(diag.augmentationWithoutDeclaration, 54, 7),
],
);
}
test_class_instanceField_augments_staticGetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static int get foo => 0;',
augmentation: 'int foo = 0;',
conflictAtAugmentation: false,
);
}
test_class_instanceField_augments_staticMethod() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static void foo() {}',
augmentation: 'int foo = 0;',
conflictAtAugmentation: false,
);
}
test_class_instanceField_augments_staticSetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static set foo(int _) {}',
augmentation: 'int foo = 0;',
conflictAtAugmentation: false,
);
}
test_class_instanceGetter() async {
await assertErrorsInCode(
r'''
class A {}
@@ -88,20 +169,60 @@ augment class A {
);
}
test_class_getter_static() async {
test_class_instanceGetter_augments_constructor() async {
await assertErrorsInCode(
r'''
class A {}
class A {
A.foo();
}
augment class A {
augment static int get foo => 0;
augment int get foo => 0;
}
''',
[error(diag.augmentationWithoutDeclaration, 32, 7)],
[error(diag.augmentationWithoutDeclaration, 44, 7)],
);
}
test_class_method() async {
test_class_instanceGetter_augments_staticField() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static int foo = 0;',
augmentation: 'int get foo => 0;',
expectConflict: false,
);
}
test_class_instanceGetter_augments_staticGetter() async {
await assertErrorsInCode(
r'''
class A {
static int get foo => 0;
}
augment class A {
augment int get foo => 0;
}
''',
[error(diag.augmentationWithoutDeclaration, 59, 7)],
);
}
test_class_instanceGetter_augments_staticMethod() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static void foo() {}',
augmentation: 'int get foo => 0;',
expectConflict: false,
);
}
test_class_instanceGetter_augments_staticSetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static set foo(int _) {}',
augmentation: 'int get foo => 0;',
expectConflict: false,
);
}
test_class_instanceMethod() async {
await assertErrorsInCode(
r'''
class A {}
@@ -114,20 +235,22 @@ augment class A {
);
}
test_class_method_static() async {
test_class_instanceMethod_augments_constructor() async {
await assertErrorsInCode(
r'''
class A {}
class A {
A.foo();
}
augment class A {
augment static void foo() {}
augment void foo() {}
}
''',
[error(diag.augmentationWithoutDeclaration, 32, 7)],
[error(diag.augmentationWithoutDeclaration, 44, 7)],
);
}
test_class_method_valid() async {
test_class_instanceMethod_augments_instanceMethod() async {
await assertNoErrorsInCode(r'''
class A {
void foo() {}
@@ -139,7 +262,45 @@ augment class A {
''');
}
test_class_setter() async {
test_class_instanceMethod_augments_staticField() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static int foo = 0;',
augmentation: 'void foo() {}',
expectConflict: false,
);
}
test_class_instanceMethod_augments_staticGetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static int get foo => 0;',
augmentation: 'void foo() {}',
expectConflict: false,
);
}
test_class_instanceMethod_augments_staticMethod() async {
await assertErrorsInCode(
r'''
class A {
static void foo() {}
}
augment class A {
augment void foo() {}
}
''',
[error(diag.augmentationWithoutDeclaration, 55, 7)],
);
}
test_class_instanceMethod_augments_staticSetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static set foo(int _) {}',
augmentation: 'void foo() {}',
expectConflict: false,
);
}
test_class_instanceSetter() async {
await assertErrorsInCode(
r'''
class A {}
@@ -152,7 +313,213 @@ augment class A {
);
}
test_class_setter_static() async {
test_class_instanceSetter_augments_constructor() async {
await assertErrorsInCode(
r'''
class A {
A.foo();
}
augment class A {
augment set foo(int _) {}
}
''',
[error(diag.augmentationWithoutDeclaration, 44, 7)],
);
}
test_class_instanceSetter_augments_staticField() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static int foo = 0;',
augmentation: 'set foo(int _) {}',
expectConflict: false,
);
}
test_class_instanceSetter_augments_staticGetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static int get foo => 0;',
augmentation: 'set foo(int _) {}',
expectConflict: false,
);
}
test_class_instanceSetter_augments_staticMethod() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'static void foo() {}',
augmentation: 'set foo(int _) {}',
expectConflict: false,
);
}
test_class_instanceSetter_augments_staticSetter() async {
await assertErrorsInCode(
r'''
class A {
static set foo(int _) {}
}
augment class A {
augment set foo(int _) {}
}
''',
[error(diag.augmentationWithoutDeclaration, 59, 7)],
);
}
test_class_staticField() async {
await assertErrorsInCode(
r'''
class A {}
augment class A {
augment static int foo = 0;
}
''',
[error(diag.augmentationWithoutDeclaration, 32, 7)],
);
}
test_class_staticField_augments_instanceField() async {
await assertErrorsInCode(
r'''
class A {
int foo = 0;
}
augment class A {
augment static int foo = 0;
}
''',
[
error(diag.augmentationWithoutDeclaration, 47, 7),
error(diag.conflictingStaticAndInstance, 66, 3),
],
);
}
test_class_staticField_augments_instanceGetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'int get foo => 0;',
augmentation: 'static int foo = 0;',
);
}
test_class_staticField_augments_instanceMethod() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'void foo() {}',
augmentation: 'static int foo = 0;',
);
}
test_class_staticField_augments_instanceSetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'set foo(int _) {}',
augmentation: 'static int foo = 0;',
);
}
test_class_staticGetter() async {
await assertErrorsInCode(
r'''
class A {}
augment class A {
augment static int get foo => 0;
}
''',
[error(diag.augmentationWithoutDeclaration, 32, 7)],
);
}
test_class_staticGetter_augments_instanceField() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'int foo = 0;',
augmentation: 'static int get foo => 0;',
);
}
test_class_staticGetter_augments_instanceGetter() async {
await assertErrorsInCode(
r'''
class A {
int get foo => 0;
}
augment class A {
augment static int get foo => 0;
}
''',
[
error(diag.augmentationWithoutDeclaration, 52, 7),
error(diag.conflictingStaticAndInstance, 75, 3),
],
);
}
test_class_staticGetter_augments_instanceMethod() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'void foo() {}',
augmentation: 'static int get foo => 0;',
);
}
test_class_staticGetter_augments_instanceSetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'set foo(int _) {}',
augmentation: 'static int get foo => 0;',
);
}
test_class_staticMethod() async {
await assertErrorsInCode(
r'''
class A {}
augment class A {
augment static void foo() {}
}
''',
[error(diag.augmentationWithoutDeclaration, 32, 7)],
);
}
test_class_staticMethod_augments_instanceField() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'int foo = 0;',
augmentation: 'static void foo() {}',
);
}
test_class_staticMethod_augments_instanceGetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'int get foo => 0;',
augmentation: 'static void foo() {}',
);
}
test_class_staticMethod_augments_instanceMethod() async {
await assertErrorsInCode(
r'''
class A {
void foo() {}
}
augment class A {
augment static void foo() {}
}
''',
[
error(diag.augmentationWithoutDeclaration, 48, 7),
error(diag.conflictingStaticAndInstance, 68, 3),
],
);
}
test_class_staticMethod_augments_instanceSetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'set foo(int _) {}',
augmentation: 'static void foo() {}',
);
}
test_class_staticSetter() async {
await assertErrorsInCode(
r'''
class A {}
@@ -165,12 +532,42 @@ augment class A {
);
}
test_class_valid() async {
await assertNoErrorsInCode(r'''
class A {}
test_class_staticSetter_augments_instanceField() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'int foo = 0;',
augmentation: 'static set foo(int _) {}',
);
}
augment class A {}
''');
test_class_staticSetter_augments_instanceGetter() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'int get foo => 0;',
augmentation: 'static set foo(int _) {}',
);
}
test_class_staticSetter_augments_instanceMethod() async {
await _assertClassMemberAugmentationWithoutDeclaration(
declaration: 'void foo() {}',
augmentation: 'static set foo(int _) {}',
);
}
test_class_staticSetter_augments_instanceSetter() async {
await assertErrorsInCode(
r'''
class A {
set foo(int _) {}
}
augment class A {
augment static set foo(int _) {}
}
''',
[
error(diag.augmentationWithoutDeclaration, 52, 7),
error(diag.conflictingStaticAndInstance, 71, 3),
],
);
}
test_enum() async {
@@ -201,7 +598,7 @@ augment enum A {;
);
}
test_enum_field() async {
test_enum_instanceField() async {
await assertErrorsInCode(
r'''
enum A {
@@ -217,7 +614,7 @@ augment enum A {;
);
}
test_enum_getter() async {
test_enum_instanceGetter() async {
await assertErrorsInCode(
r'''
enum A {
@@ -233,7 +630,7 @@ augment enum A {;
);
}
test_enum_method() async {
test_enum_instanceMethod() async {
await assertErrorsInCode(
r'''
enum A {
@@ -249,7 +646,7 @@ augment enum A {;
);
}
test_enum_setter() async {
test_enum_instanceSetter() async {
await assertErrorsInCode(
r'''
enum A {
@@ -274,7 +671,7 @@ augment extension A {}
);
}
test_extension_getter() async {
test_extension_instanceGetter() async {
await assertErrorsInCode(
r'''
extension A on int {}
@@ -287,7 +684,7 @@ augment extension A {
);
}
test_extension_method() async {
test_extension_instanceMethod() async {
await assertErrorsInCode(
r'''
extension A on int {}
@@ -300,7 +697,7 @@ augment extension A {
);
}
test_extension_setter() async {
test_extension_instanceSetter() async {
await assertErrorsInCode(
r'''
extension A on int {}
@@ -335,7 +732,7 @@ augment extension type A(int it) {
);
}
test_extensionType_getter() async {
test_extensionType_instanceGetter() async {
await assertErrorsInCode(
r'''
extension type A(int it) {}
@@ -348,7 +745,7 @@ augment extension type A(int it) {
);
}
test_extensionType_method() async {
test_extensionType_instanceMethod() async {
await assertErrorsInCode(
r'''
extension type A(int it) {}
@@ -361,7 +758,7 @@ augment extension type A(int it) {
);
}
test_extensionType_setter() async {
test_extensionType_instanceSetter() async {
await assertErrorsInCode(
r'''
extension type A(int it) {}
@@ -383,7 +780,7 @@ augment mixin A {}
);
}
test_mixin_field() async {
test_mixin_instanceField() async {
await assertErrorsInCode(
r'''
mixin A {}
@@ -396,7 +793,7 @@ augment mixin A {
);
}
test_mixin_getter() async {
test_mixin_instanceGetter() async {
await assertErrorsInCode(
r'''
mixin A {}
@@ -409,7 +806,7 @@ augment mixin A {
);
}
test_mixin_method() async {
test_mixin_instanceMethod() async {
await assertErrorsInCode(
r'''
mixin A {}
@@ -422,7 +819,7 @@ augment mixin A {
);
}
test_mixin_method_valid() async {
test_mixin_instanceMethod_augments_instanceMethod() async {
await assertNoErrorsInCode(r'''
mixin A {
void foo() {}
@@ -434,7 +831,7 @@ augment mixin A {
''');
}
test_mixin_setter() async {
test_mixin_instanceSetter() async {
await assertErrorsInCode(
r'''
mixin A {}
@@ -456,7 +853,7 @@ augment void foo() {}
);
}
test_topLevel_function_valid() async {
test_topLevel_function_augments_function() async {
await assertNoErrorsInCode(r'''
void foo() {}
@@ -511,11 +908,44 @@ augment int foo = 0;
);
}
test_topLevel_variable_single_valid() async {
test_topLevel_variable_single_augments_variable() async {
await assertNoErrorsInCode(r'''
int foo = 0;
augment int foo = 1;
''');
}
Future<void> _assertClassMemberAugmentationWithoutDeclaration({
required String declaration,
required String augmentation,
bool conflictAtAugmentation = true,
bool expectConflict = true,
}) async {
var code =
'''
class A {
$declaration
}
augment class A {
augment $augmentation
}
''';
await assertErrorsInCode(code, [
if (expectConflict)
error(
diag.conflictingStaticAndInstance,
conflictAtAugmentation
? code.lastIndexOf('foo')
: code.indexOf('foo'),
3,
),
error(
diag.augmentationWithoutDeclaration,
code.indexOf('augment $augmentation'),
7,
),
]);
}
}
@@ -363,6 +363,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
_writeDocumentation(e.documentationComment);
_writeMetadata(e.metadata);
_writeSinceSdkVersion(e);
@@ -583,6 +587,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
_writeDocumentation(e.documentationComment);
_writeMetadata(e.metadata);
_writeSinceSdkVersion(e);
@@ -891,6 +899,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
_writeDocumentation(e.documentationComment);
_writeMetadata(e.metadata);
_writeSinceSdkVersion(e);
@@ -998,6 +1010,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
_writeDocumentation(e.documentationComment);
// _writeMetadata(e.metadata);
_writeSinceSdkVersion(e);
@@ -1259,6 +1275,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
// _writeElementReference(e.enclosingElement, label: 'enclosingElement');
_writeDocumentation(e.documentationComment);
_writeMetadata(e.metadata);
@@ -1441,6 +1461,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
_writeDocumentation(e.documentationComment);
_writeMetadata(e.metadata);
_writeSinceSdkVersion(e);
@@ -1532,6 +1556,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
_writeDocumentation(e.documentationComment);
_writeMetadata(e.metadata);
_writeSinceSdkVersion(e);
@@ -1625,6 +1653,10 @@ class _Element2Writer extends _AbstractElementWriter {
_sink.withIndent(() {
_writeReference(e);
_writeFragmentReference('firstFragment', e.firstFragment);
_writeFragmentReference(
'previousFragmentOfDifferentKind',
e.previousFragmentOfDifferentKind,
);
_writeDocumentation(e.documentationComment);
_writeMetadata(e.metadata);
_writeSinceSdkVersion(e);
File diff suppressed because it is too large Load Diff
@@ -13728,6 +13728,7 @@ library
isOriginDeclaration foo
reference: <testLibrary>::@enum::A::@setter::foo
firstFragment: #F12
previousFragmentOfDifferentKind: #F5
formalParameters
#E0 requiredPositional _
firstFragment: #F13
@@ -17969,6 +17970,7 @@ library
isOriginDeclaration foo
reference: <testLibrary>::@enum::A::@setter::foo
firstFragment: #F10
previousFragmentOfDifferentKind: #F5
formalParameters
#E0 requiredPositional _
firstFragment: #F11
@@ -18324,6 +18326,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F3
enums
isSimplyBounded enum A
reference: <testLibrary>::@enum::A
@@ -18432,6 +18435,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F2
enums
isSimplyBounded enum A
reference: <testLibrary>::@enum::A::@def::0
@@ -18468,6 +18472,7 @@ library
isSimplyBounded enum A
reference: <testLibrary>::@enum::A::@def::1
firstFragment: #F7
previousFragmentOfDifferentKind: #F1
supertype: Enum
fields
isConst isOriginEnumValues isStatic values
@@ -2942,6 +2942,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F3
extensions
extension A
reference: <testLibrary>::@extension::A
@@ -2979,6 +2980,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F2
extensions
extension A
reference: <testLibrary>::@extension::A::@def::0
@@ -2988,6 +2990,7 @@ library
extension A
reference: <testLibrary>::@extension::A::@def::1
firstFragment: #F3
previousFragmentOfDifferentKind: #F1
extendedType: InvalidType
onDeclaration: <null>
''');
@@ -12019,6 +12019,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F3
extensionTypes
isSimplyBounded extension type A
reference: <testLibrary>::@extensionType::A
@@ -12082,6 +12083,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F2
extensionTypes
isSimplyBounded extension type A
reference: <testLibrary>::@extensionType::A::@def::0
@@ -12105,6 +12107,7 @@ library
isSimplyBounded extension type A
reference: <testLibrary>::@extensionType::A::@def::1
firstFragment: #F5
previousFragmentOfDifferentKind: #F1
representation: <testLibrary>::@extensionType::A::@def::1::@field::it
primaryConstructor: <testLibrary>::@extensionType::A::@def::1::@constructor::new
typeErasure: int
@@ -4499,6 +4499,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F3
mixins
isSimplyBounded mixin A
reference: <testLibrary>::@mixin::A
@@ -4538,6 +4539,7 @@ library
isSimplyBounded class A
reference: <testLibrary>::@class::A
firstFragment: #F1
previousFragmentOfDifferentKind: #F3
constructors
isOriginImplicitDefault new
reference: <testLibrary>::@class::A::@constructor::new
@@ -4551,6 +4553,7 @@ library
isSimplyBounded mixin A
reference: <testLibrary>::@mixin::A::@def::1
firstFragment: #F4
previousFragmentOfDifferentKind: #F1
superclassConstraints
Object
''');
@@ -1280,6 +1280,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@function::foo
firstFragment: #F3
previousFragmentOfDifferentKind: #F2
returnType: void
''');
}
@@ -1355,6 +1356,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@function::foo
firstFragment: #F4
previousFragmentOfDifferentKind: #F2
returnType: void
''');
}
@@ -1413,6 +1415,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@function::foo
firstFragment: #F5
previousFragmentOfDifferentKind: #F1
returnType: void
''');
}
@@ -1596,6 +1599,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@function::foo
firstFragment: #F3
previousFragmentOfDifferentKind: #F1
returnType: void
''');
}
@@ -2908,6 +2908,7 @@ library
isOriginDeclaration isStatic A
reference: <testLibrary>::@getter::A
firstFragment: #F4
previousFragmentOfDifferentKind: #F1
returnType: int
variable: <testLibrary>::@topLevelVariable::A
exportedReferences
@@ -2949,6 +2950,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@getter::foo
firstFragment: #F2
previousFragmentOfDifferentKind: #F3
returnType: int
variable: <testLibrary>::@topLevelVariable::foo
functions
@@ -3319,6 +3321,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@getter::foo
firstFragment: #F2
previousFragmentOfDifferentKind: #F3
returnType: int
variable: <testLibrary>::@topLevelVariable::foo
setters
@@ -3654,6 +3657,7 @@ library
isOriginDeclaration isStatic A
reference: <testLibrary>::@setter::A
firstFragment: #F4
previousFragmentOfDifferentKind: #F1
formalParameters
#E0 requiredPositional _
firstFragment: #F5
@@ -3704,6 +3708,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@setter::foo
firstFragment: #F2
previousFragmentOfDifferentKind: #F4
formalParameters
#E0 requiredPositional _
firstFragment: #F3
@@ -3766,6 +3771,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@setter::foo
firstFragment: #F3
previousFragmentOfDifferentKind: #F2
formalParameters
#E0 requiredPositional _
firstFragment: #F4
@@ -3823,6 +3829,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@setter::foo
firstFragment: #F3
previousFragmentOfDifferentKind: #F2
formalParameters
#E0 requiredPositional _
firstFragment: #F4
@@ -4287,6 +4294,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@setter::foo
firstFragment: #F3
previousFragmentOfDifferentKind: #F1
metadata
Annotation
atSign: @ @15
@@ -4358,6 +4366,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@setter::foo
firstFragment: #F3
previousFragmentOfDifferentKind: #F1
formalParameters
#E0 requiredPositional _
firstFragment: #F4
@@ -4473,6 +4482,7 @@ library
isOriginDeclaration isStatic foo
reference: <testLibrary>::@setter::foo
firstFragment: #F3
previousFragmentOfDifferentKind: #F1
formalParameters
#E0 requiredPositional _
firstFragment: #F4
@@ -4532,6 +4542,7 @@ library
hasInitializer isOriginDeclaration isStatic A
reference: <testLibrary>::@topLevelVariable::A
firstFragment: #F3
previousFragmentOfDifferentKind: #F1
type: int
getter: <testLibrary>::@getter::A
setter: <testLibrary>::@setter::A
@@ -4592,6 +4603,7 @@ library
hasInitializer isOriginDeclaration isStatic foo
reference: <testLibrary>::@topLevelVariable::foo
firstFragment: #F1
previousFragmentOfDifferentKind: #F5
type: int
getter: <testLibrary>::@getter::foo
setter: <testLibrary>::@setter::foo