| // 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:analysis_server/src/utilities/extensions/selection.dart'; | |
| import 'package:analysis_server_plugin/src/utilities/selection.dart'; | |
| import 'package:analyzer/dart/element/element.dart'; | |
| import 'package:analyzer/source/source_range.dart'; | |
| import 'package:analyzer_testing/src/single_unit.dart'; | |
| import 'package:test/test.dart'; | |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| void main() { | |
| defineReflectiveSuite(() { | |
| defineReflectiveTests(SelectionConstructorInClassTest); | |
| defineReflectiveTests(SelectionConstructorInEnumTest); | |
| defineReflectiveTests(SelectionConstructorInExtensionTypeTest); | |
| }); | |
| } | |
| /// This class has all of the invocation site tests because the structure of the | |
| /// AST at the invocation site doesn't depend on the kind of declaration | |
| /// containing the constructor declaration. | |
| @reflectiveTest | |
| class SelectionConstructorInClassTest extends _SelectionConstructorTestBase { | |
| Future<void> test_declaration_inBody_factory_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| class C { | |
| factory na^me() => C._(); | |
| C._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_factory_named_onFactory() async { | |
| await resolveTestCode(''' | |
| class C { | |
| facto^ry name() => C._(); | |
| C._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_factory_named_overBoth() async { | |
| await resolveTestCode(''' | |
| class C { | |
| fact[!ory na!]me() => C._(); | |
| C._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_factory_unnamed() async { | |
| await resolveTestCode(''' | |
| class C { | |
| facto^ry () => C._(); | |
| C._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| class C { | |
| new na^me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_named_onNew() async { | |
| await resolveTestCode(''' | |
| class C { | |
| ne^w name(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_named_overBoth() async { | |
| await resolveTestCode(''' | |
| class C { | |
| ne[!w na!]me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_unnamed() async { | |
| await resolveTestCode(''' | |
| class C { | |
| ^new (); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_named_onClassName() async { | |
| await resolveTestCode(''' | |
| class C { | |
| ^C.name(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| class C { | |
| C.na^me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_named_overBoth() async { | |
| await resolveTestCode(''' | |
| class C { | |
| [!C.na!]me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_unnamed() async { | |
| await resolveTestCode(''' | |
| class C { | |
| ^C(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| class C.n^ame() {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_onContainerName() async { | |
| await resolveTestCode(''' | |
| class C^.name() {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_overBoth() async { | |
| await resolveTestCode(''' | |
| class [!C.nam!]e() {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_onKeyword() async { | |
| await resolveTestCode(''' | |
| cla^ss C() {} | |
| '''); | |
| _assertNoConstructor(); | |
| } | |
| Future<void> test_declaration_primary_unnamed() async { | |
| await resolveTestCode(''' | |
| class C^() {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_invocation_named_onArgumentList() async { | |
| await resolveTestCode(''' | |
| class C { | |
| C.name(); | |
| } | |
| void f() { | |
| C.name(^); | |
| } | |
| '''); | |
| _assertNoConstructor(); | |
| } | |
| Future<void> test_invocation_named_onClassName() async { | |
| await resolveTestCode(''' | |
| class C { | |
| C.name(); | |
| } | |
| void f() { | |
| ^C.name(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_invocation_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| class C { | |
| C.name(); | |
| } | |
| void f() { | |
| C.^name(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_invocation_named_overBoth() async { | |
| await resolveTestCode(''' | |
| class C { | |
| C.name(); | |
| } | |
| void f() { | |
| [!C.nam!]e(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_invocation_unnamed() async { | |
| await resolveTestCode(''' | |
| class C() {} | |
| void f() { | |
| ^C(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| } | |
| @reflectiveTest | |
| class SelectionConstructorInEnumTest extends _SelectionConstructorTestBase { | |
| Future<void> test_declaration_inBody_factory_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a._(); | |
| factory na^me() => a; | |
| const E._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_factory_named_onFactory() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a._(); | |
| facto^ry name() => a; | |
| const E._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_factory_named_overBoth() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a._(); | |
| fa[!ctory na!]me() => a; | |
| const E._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_factory_unnamed() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a._(); | |
| facto^ry () => a; | |
| const E._(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a.name(); | |
| const new na^me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_named_onNew() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a.name(); | |
| const new^ name(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_named_overBoth() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a.name(); | |
| const ne[!w na!]me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_new_unnamed() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a(); | |
| const ^new (); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a.name(); | |
| const E.na^me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_named_onEnumName() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a.name(); | |
| const E^.name(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_named_overBoth() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a.name(); | |
| const [!E.na!]me(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_inBody_simple_unnamed() async { | |
| await resolveTestCode(''' | |
| enum E { | |
| a(); | |
| const E^(); | |
| } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| enum E.n^ame() { a.name() } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_onContainerName() async { | |
| await resolveTestCode(''' | |
| enum E^.name() { a.name() } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_overBoth() async { | |
| await resolveTestCode(''' | |
| enum [!E.nam!]e() { a.name() } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_onKeyword() async { | |
| await resolveTestCode(''' | |
| en^um E() { a } | |
| '''); | |
| _assertNoConstructor(); | |
| } | |
| Future<void> test_declaration_primary_unnamed() async { | |
| await resolveTestCode(''' | |
| enum E^() { a } | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| } | |
| @reflectiveTest | |
| class SelectionConstructorInExtensionTypeTest | |
| extends _SelectionConstructorTestBase { | |
| Future<void> test_declaration_primary_named_onConstructorName() async { | |
| await resolveTestCode(''' | |
| extension type E.n^ame(int x) {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_onContainerName() async { | |
| await resolveTestCode(''' | |
| extension type E^.name(int x) {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_named_overBoth() async { | |
| await resolveTestCode(''' | |
| extension type [!E.nam!]e(int x) {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| Future<void> test_declaration_primary_onExtensionKeyword() async { | |
| await resolveTestCode(''' | |
| exten^sion type E(int x) {} | |
| '''); | |
| _assertNoConstructor(); | |
| } | |
| Future<void> test_declaration_primary_onTypeKeyword() async { | |
| await resolveTestCode(''' | |
| extension ^type E(int x) {} | |
| '''); | |
| _assertNoConstructor(); | |
| } | |
| Future<void> test_declaration_primary_unnamed() async { | |
| await resolveTestCode(''' | |
| extension type E^(int x) {} | |
| '''); | |
| _assertHasConstructor(); | |
| } | |
| } | |
| abstract class _SelectionConstructorTestBase extends SingleUnitTest { | |
| void _assertHasConstructor() { | |
| expect(_getConstructor(), isA<ConstructorElement>()); | |
| } | |
| void _assertNoConstructor() { | |
| expect(_getConstructor(), isNull); | |
| } | |
| ConstructorElement? _getConstructor() { | |
| var range = _getSourceRange(); | |
| var selection = testAnalysisResult.unit.select( | |
| offset: range.offset, | |
| length: range.length, | |
| ); | |
| if (selection == null) { | |
| fail('No selection found'); | |
| } | |
| return selection.constructor(); | |
| } | |
| SourceRange _getSourceRange() { | |
| if (parsedTestCode.positions.length == 1) { | |
| return SourceRange(parsedTestCode.position.offset, 0); | |
| } else if (parsedTestCode.ranges.length == 1) { | |
| return parsedTestCode.range.sourceRange; | |
| } else { | |
| fail('Invalid source range in test code.'); | |
| } | |
| } | |
| } |