Suggest constructor tearoffs in const context.
Fixes https://github.com/dart-lang/sdk/issues/42264.
Change-Id: I19767d9afffd9270dedde71cad695ec439279674
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357240
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
index 231a82a..30ec817 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
@@ -141,7 +141,9 @@
{required InterfaceType type, String? exclude}) {
for (var constructor in type.constructors) {
var name = constructor.name;
- if (name.isNotEmpty && name != exclude) {
+ if (name.isNotEmpty &&
+ name != exclude &&
+ !(mustBeConstant && !constructor.isConst)) {
_suggestConstructor(
constructor,
hasClassName: true,
@@ -1050,7 +1052,7 @@
required bool hasClassName,
required bool isConstructorRedirect,
}) {
- if (mustBeAssignable || (mustBeConstant && !element.isConst)) {
+ if (mustBeAssignable) {
return;
}
@@ -1058,11 +1060,13 @@
return;
}
+ var isTearOff = preferNonInvocation || (mustBeConstant && !element.isConst);
+
var suggestion = ConstructorSuggestion(
importData: importData,
element: element,
hasClassName: hasClassName,
- isTearOff: preferNonInvocation,
+ isTearOff: isTearOff,
isRedirect: isConstructorRedirect,
);
collector.addSuggestion(suggestion);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
index 6ab6819..2a275a9 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
@@ -2444,11 +2444,12 @@
void _forCollectionElement(
TypedLiteral literal, NodeList<CollectionElement> elements) {
var mustBeStatic = literal.inStaticContext;
+ var mustBeConst = literal.inConstantContext;
keywordHelper.addCollectionElementKeywords(literal, elements,
- mustBeStatic: mustBeStatic);
- var preceedingElement = elements.elementBefore(offset);
- declarationHelper(mustBeStatic: mustBeStatic)
- .addLexicalDeclarations(preceedingElement ?? literal);
+ mustBeConst: mustBeConst, mustBeStatic: mustBeStatic);
+ var precedingElement = elements.elementBefore(offset);
+ declarationHelper(mustBeStatic: mustBeStatic, mustBeConstant: mustBeConst)
+ .addLexicalDeclarations(precedingElement ?? literal);
}
/// Add the suggestions that are appropriate when completing in the given
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart
index 92a5c2c..a139527 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart
@@ -103,7 +103,7 @@
/// beginning of an element in a collection [literal].
void addCollectionElementKeywords(
TypedLiteral literal, NodeList<CollectionElement> elements,
- {bool mustBeStatic = false}) {
+ {bool mustBeConst = false, bool mustBeStatic = false}) {
// TODO(brianwilkerson): Consider determining whether there is a comma before
// the selection and inserting the comma if there isn't one.
addKeyword(Keyword.FOR);
@@ -126,7 +126,8 @@
}
}
}
- addExpressionKeywords(literal, mustBeStatic: mustBeStatic);
+ addExpressionKeywords(literal,
+ mustBeConstant: mustBeConst, mustBeStatic: mustBeStatic);
}
/// Add the keywords that are appropriate when the selection is after the
diff --git a/pkg/analysis_server/test/services/completion/dart/declaration/constructor_test.dart b/pkg/analysis_server/test/services/completion/dart/declaration/constructor_test.dart
index 3ea727b..7a8013f 100644
--- a/pkg/analysis_server/test/services/completion/dart/declaration/constructor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/declaration/constructor_test.dart
@@ -18,6 +18,34 @@
with ConstructorTestCases {}
mixin ConstructorTestCases on AbstractCompletionDriverTest {
+ Future<void> test_constContext_constructorTearOff() async {
+ allowedIdentifiers = const {'NotAConst'};
+ newFile('$testPackageLibPath/a.dart', '''
+class A {
+ const A(List<Object> any);
+}
+
+class NotAConst {}
+''');
+ await computeSuggestions('''
+import 'a.dart';
+
+ @A([
+ N^
+ ])
+ class E {}
+''');
+ assertResponse(r'''
+replacement
+ left: 1
+suggestions
+ NotAConst.new
+ kind: constructor
+ null
+ kind: keyword
+''');
+ }
+
Future<void> test_noKeyword() async {
newFile('$testPackageLibPath/a.dart', '''
class A0 {
diff --git a/pkg/analysis_server/test/services/completion/dart/declaration/imported_reference_test.dart b/pkg/analysis_server/test/services/completion/dart/declaration/imported_reference_test.dart
index 2c12cff..1176744 100644
--- a/pkg/analysis_server/test/services/completion/dart/declaration/imported_reference_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/declaration/imported_reference_test.dart
@@ -1742,8 +1742,12 @@
suggestions
B0
kind: constructorInvocation
+ B0.named
+ kind: constructor
B0.namedConst
kind: constructorInvocation
+ C0.new
+ kind: constructor
b0
kind: topLevelVariable
''');
@@ -2305,6 +2309,12 @@
kind: class
A0
kind: constructorInvocation
+ A0.new
+ kind: constructor
+ String.fromCharCode
+ kind: constructor
+ String.fromCharCodes
+ kind: constructor
String.fromEnvironment
kind: constructorInvocation
f0
diff --git a/pkg/analysis_server/test/services/completion/dart/declaration/local_reference_test.dart b/pkg/analysis_server/test/services/completion/dart/declaration/local_reference_test.dart
index 759e938..979835c 100644
--- a/pkg/analysis_server/test/services/completion/dart/declaration/local_reference_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/declaration/local_reference_test.dart
@@ -2741,6 +2741,8 @@
kind: class
A0
kind: constructorInvocation
+ A0.new
+ kind: constructor
f0
kind: functionInvocation
''');
diff --git a/pkg/analysis_server/test/services/completion/dart/declaration/type_member_test.dart b/pkg/analysis_server/test/services/completion/dart/declaration/type_member_test.dart
index 583900b..897be50 100644
--- a/pkg/analysis_server/test/services/completion/dart/declaration/type_member_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/declaration/type_member_test.dart
@@ -1898,6 +1898,8 @@
kind: class
A0
kind: constructorInvocation
+ A0.new
+ kind: constructor
f0
kind: functionInvocation
''');
diff --git a/pkg/analysis_server/test/services/completion/dart/location/if_statement_test.dart b/pkg/analysis_server/test/services/completion/dart/location/if_statement_test.dart
index 73f10e9..421792f 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/if_statement_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/if_statement_test.dart
@@ -38,7 +38,7 @@
A1
kind: class
A1.named
- kind: constructorInvocation
+ kind: constructor
c01
kind: topLevelVariable
const
diff --git a/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart b/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart
index 24ea2c2..128a942 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart
@@ -59,6 +59,8 @@
kind: class
A1
kind: constructorInvocation
+ A1.new
+ kind: constructor
const
kind: keyword
false
@@ -97,7 +99,7 @@
A1
kind: class
A1.named
- kind: constructorInvocation
+ kind: constructor
c01
kind: topLevelVariable
const