Fix code completion before keyword in constructor

This fixes an exeception when code completing before the `new` or
`factory` keyword in a constructor and the type name is not explicitly
used. The exception prevents any suggestions from being returned, so
it's fairly serious.

Change-Id: I2f5028812ee1945ac9635f55953fb800b19a48c5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/505620
Auto-Submit: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Brian Wilkerson
2026-05-22 10:25:06 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent d7d723327f
commit 1e1ecd8b41
2 changed files with 135 additions and 2 deletions
@@ -772,8 +772,11 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
// TODO(scheglov): support primary constructors
if (offset <= node.typeName!.end) {
if (offset <=
(node.typeName?.end ??
node.newKeyword?.end ??
node.factoryKeyword?.end ??
node.beginToken.offset)) {
collector.completionLocation = 'ClassDeclaration_member';
var parent = node.parent?.parent;
if (parent != null) {
@@ -17,6 +17,136 @@ class ConstructorDeclarationTest extends AbstractCompletionDriverTest
with ConstructorDeclarationTestCases {}
mixin ConstructorDeclarationTestCases on AbstractCompletionDriverTest {
Future<void> test_beforeFactory() async {
await computeSuggestions('''
class C {
^factory ();
}
''');
assertResponse(r'''
replacement
right: 7
suggestions
@override
// TODO: implement hashCode
int get hashCode => [!super.hashCode!];
kind: override
@override
// TODO: implement runtimeType
Type get runtimeType => [!super.runtimeType!];
kind: override
@override
String toString() {
// TODO: implement toString
[!return super.toString();!]
}
kind: override
@override
bool operator ==(Object other) {
// TODO: implement ==
[!return super == other;!]
}
kind: override
@override
noSuchMethod(Invocation invocation) {
// TODO: implement noSuchMethod
[!return super.noSuchMethod(invocation);!]
}
kind: override
final
kind: keyword
static
kind: keyword
void
kind: keyword
const
kind: keyword
set
kind: keyword
factory
kind: keyword
covariant
kind: keyword
dynamic
kind: keyword
get
kind: keyword
late
kind: keyword
new
kind: keyword
operator
kind: keyword
var
kind: keyword
''');
}
Future<void> test_beforeNew() async {
await computeSuggestions('''
class C {
^new ();
}
''');
assertResponse(r'''
replacement
right: 3
suggestions
@override
// TODO: implement hashCode
int get hashCode => [!super.hashCode!];
kind: override
@override
// TODO: implement runtimeType
Type get runtimeType => [!super.runtimeType!];
kind: override
@override
String toString() {
// TODO: implement toString
[!return super.toString();!]
}
kind: override
@override
bool operator ==(Object other) {
// TODO: implement ==
[!return super == other;!]
}
kind: override
@override
noSuchMethod(Invocation invocation) {
// TODO: implement noSuchMethod
[!return super.noSuchMethod(invocation);!]
}
kind: override
final
kind: keyword
static
kind: keyword
void
kind: keyword
const
kind: keyword
set
kind: keyword
factory
kind: keyword
covariant
kind: keyword
dynamic
kind: keyword
get
kind: keyword
late
kind: keyword
new
kind: keyword
operator
kind: keyword
var
kind: keyword
''');
}
Future<void> test_factory_noInstanceValues() async {
await computeSuggestions('''
class A {