Add completion support for the new mixin syntax
Change-Id: I3a8744e03f32092c15f1e340e0ee6bef5245a859
Reviewed-on: https://dart-review.googlesource.com/72520
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Dan Rubel <danrubel@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 8079bf0..1db3c05 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -188,11 +188,20 @@
if (previousMember.leftBracket == null ||
previousMember.leftBracket.isSynthetic) {
// If the prior member is an unfinished class declaration
- // then the user is probably finishing that
+ // then the user is probably finishing that.
_addClassDeclarationKeywords(previousMember);
return;
}
}
+ if (previousMember is MixinDeclaration) {
+ if (previousMember.leftBracket == null ||
+ previousMember.leftBracket.isSynthetic) {
+ // If the prior member is an unfinished mixin declaration
+ // then the user is probably finishing that.
+ _addMixinDeclarationKeywords(previousMember);
+ return;
+ }
+ }
if (previousMember is ImportDirective) {
if (previousMember.semicolon == null ||
previousMember.semicolon.isSynthetic) {
@@ -464,6 +473,28 @@
}
@override
+ visitMixinDeclaration(MixinDeclaration node) {
+ // Don't suggest mixin name
+ if (entity == node.name) {
+ return;
+ }
+ if (entity == node.rightBracket) {
+ _addClassBodyKeywords();
+ } else if (entity is ClassMember) {
+ _addClassBodyKeywords();
+ int index = node.members.indexOf(entity);
+ ClassMember previous = index > 0 ? node.members[index - 1] : null;
+ if (previous is MethodDeclaration && isEmptyBody(previous.body)) {
+ _addSuggestion(Keyword.ASYNC);
+ _addSuggestion2(ASYNC_STAR);
+ _addSuggestion2(SYNC_STAR);
+ }
+ } else {
+ _addMixinDeclarationKeywords(node);
+ }
+ }
+
+ @override
visitNamedExpression(NamedExpression node) {
if (entity is SimpleIdentifier && entity == node.expression) {
_addExpressionKeywords(node);
@@ -644,6 +675,17 @@
}
}
+ void _addMixinDeclarationKeywords(MixinDeclaration node) {
+ // Very simplistic suggestion because analyzer will warn if
+ // the on / implements clauses are out of order
+ if (node.onClause == null) {
+ _addSuggestion(Keyword.ON, DART_RELEVANCE_HIGH);
+ }
+ if (node.implementsClause == null) {
+ _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH);
+ }
+ }
+
void _addStatementKeywords(AstNode node) {
if (_inClassMemberBody(node)) {
_addSuggestions([Keyword.SUPER, Keyword.THIS]);
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index 8568c03..f2e2ba2 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -1668,6 +1668,19 @@
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
+ test_mixin() async {
+ addTestSource('mixin M o^ { }');
+ await computeSuggestions();
+ assertSuggestKeywords([Keyword.ON, Keyword.IMPLEMENTS],
+ relevance: DART_RELEVANCE_HIGH);
+ }
+
+ test_mixin_afterOnClause() async {
+ addTestSource('mixin M on A i^ { } class A {}');
+ await computeSuggestions();
+ assertSuggestKeywords([Keyword.IMPLEMENTS], relevance: DART_RELEVANCE_HIGH);
+ }
+
test_named_constructor_invocation() async {
addTestSource('void main() {new Future.^}');
await computeSuggestions();