improve keyword suggestions - fixes #24016

R=brianwilkerson@google.com

Review URL: https://codereview.chromium.org//1303233008 .
This commit is contained in:
Dan Rubel 2015-08-26 17:34:57 -04:00
parent 7f0916d16e
commit bd95b13b90
4 changed files with 156 additions and 18 deletions

View file

@ -157,8 +157,13 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
previous = previous.previous;
}
if (previous != null && previous.type == TokenType.EQ) {
_addSuggestions(
[Keyword.FALSE, Keyword.NEW, Keyword.NULL, Keyword.TRUE]);
_addSuggestions([
Keyword.CONST,
Keyword.FALSE,
Keyword.NEW,
Keyword.NULL,
Keyword.TRUE
]);
} else {
_addSuggestion(Keyword.IN, DART_RELEVANCE_HIGH);
}
@ -231,6 +236,15 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
}
}
@override
visitIsExpression(IsExpression node) {
if (entity == node.isOperator) {
_addSuggestion(Keyword.IS, DART_RELEVANCE_HIGH);
} else {
_addExpressionKeywords(node);
}
}
@override
visitLibraryIdentifier(LibraryIdentifier node) {
// no suggestions
@ -367,7 +381,13 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
}
void _addExpressionKeywords(AstNode node) {
_addSuggestions([Keyword.FALSE, Keyword.NEW, Keyword.NULL, Keyword.TRUE,]);
_addSuggestions([
Keyword.CONST,
Keyword.FALSE,
Keyword.NEW,
Keyword.NULL,
Keyword.TRUE,
]);
if (_inClassMemberBody(node)) {
_addSuggestions([Keyword.SUPER, Keyword.THIS,]);
}
@ -404,9 +424,15 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
if (_inAsyncMethodOrFunction(node)) {
_addSuggestion2(AWAIT);
}
if (_inLoop(node)) {
_addSuggestions([Keyword.BREAK, Keyword.CONTINUE]);
}
if (_inSwitch(node)) {
_addSuggestions([Keyword.BREAK]);
}
_addSuggestions([
Keyword.ASSERT,
Keyword.CONTINUE,
Keyword.CONST,
Keyword.DO,
Keyword.FINAL,
Keyword.FOR,
@ -434,8 +460,13 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
offset = completion.length;
}
request.addSuggestion(new CompletionSuggestion(
CompletionSuggestionKind.KEYWORD, relevance, completion, offset, 0,
false, false));
CompletionSuggestionKind.KEYWORD,
relevance,
completion,
offset,
0,
false,
false));
}
void _addSuggestions(List<Keyword> keywords,
@ -463,4 +494,20 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
node = parent;
}
}
bool _inDoLoop(AstNode node) =>
node.getAncestor((p) => p is DoStatement) != null;
bool _inForLoop(AstNode node) =>
node.getAncestor((p) => p is ForStatement || p is ForEachStatement) !=
null;
bool _inLoop(AstNode node) =>
_inDoLoop(node) || _inForLoop(node) || _inWhileLoop(node);
bool _inSwitch(AstNode node) =>
node.getAncestor((p) => p is SwitchStatement) != null;
bool _inWhileLoop(AstNode node) =>
node.getAncestor((p) => p is WhileStatement) != null;
}

View file

@ -1601,8 +1601,7 @@ main(p) {
"3-v1",
"4+is",
"4-isVariable"
],
failingTests: '4');
]);
buildTests(
'testCompletion_is_asIdentifierStart',
@ -1645,8 +1644,7 @@ main(p) {
var isVariable;
var v = p is!1
}''',
<String>["1+is", "1-isVariable"],
failingTests: '1');
<String>["1+is", "1-isVariable"]);
buildTests(
'testCompletion_keyword_in',
@ -2637,7 +2635,7 @@ class Q {
"K+else",
"L+return"
],
failingTests: '3BCHK');
failingTests: '3BCK');
// operators in function
buildTests('test015', '''f(a,b,c) => a + b * c !1;''', <String>["1+=="],

View file

@ -4291,11 +4291,12 @@ abstract class AbstractSelectorSuggestionTest extends AbstractCompletionTest {
test_SwitchStatement_case() {
// SwitchStatement Block BlockFunctionBody MethodDeclaration
addTestSource('class A {String g(int x) {switch(x) {case 0: ^}}}');
addTestSource('class A {String g(int x) {var t; switch(x) {case 0: ^}}}');
computeFast();
return computeFull((bool result) {
assertSuggestLocalClass('A');
assertSuggestLocalMethod('g', 'A', 'String');
assertSuggestLocalVariable('t', null);
assertSuggestImportedClass('String');
});
}

View file

@ -79,6 +79,28 @@ class KeywordContributorTest extends AbstractCompletionTest {
static const List<Keyword> STMT_START_IN_CLASS = const [
Keyword.ASSERT,
Keyword.CONST,
Keyword.DO,
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
Keyword.RETHROW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.SWITCH,
Keyword.THIS,
Keyword.THROW,
Keyword.TRY,
Keyword.VAR,
Keyword.VOID,
Keyword.WHILE
];
static const List<Keyword> STMT_START_IN_LOOP_IN_CLASS = const [
Keyword.ASSERT,
Keyword.BREAK,
Keyword.CONST,
Keyword.CONTINUE,
Keyword.DO,
Keyword.FINAL,
@ -99,8 +121,9 @@ class KeywordContributorTest extends AbstractCompletionTest {
static const List<Keyword> STMT_START_IN_SWITCH_IN_CLASS = const [
Keyword.ASSERT,
Keyword.BREAK,
Keyword.CASE,
Keyword.CONTINUE,
Keyword.CONST,
Keyword.DEFAULT,
Keyword.DO,
Keyword.FINAL,
@ -121,8 +144,9 @@ class KeywordContributorTest extends AbstractCompletionTest {
static const List<Keyword> STMT_START_IN_SWITCH_OUTSIDE_CLASS = const [
Keyword.ASSERT,
Keyword.BREAK,
Keyword.CASE,
Keyword.CONTINUE,
Keyword.CONST,
Keyword.DEFAULT,
Keyword.DO,
Keyword.FINAL,
@ -141,6 +165,26 @@ class KeywordContributorTest extends AbstractCompletionTest {
static const List<Keyword> STMT_START_OUTSIDE_CLASS = const [
Keyword.ASSERT,
Keyword.CONST,
Keyword.DO,
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
Keyword.NEW,
Keyword.RETHROW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
Keyword.TRY,
Keyword.VAR,
Keyword.VOID,
Keyword.WHILE
];
static const List<Keyword> STMT_START_IN_LOOP_OUTSIDE_CLASS = const [
Keyword.ASSERT,
Keyword.BREAK,
Keyword.CONST,
Keyword.CONTINUE,
Keyword.DO,
Keyword.FINAL,
@ -158,6 +202,7 @@ class KeywordContributorTest extends AbstractCompletionTest {
];
static const List<Keyword> EXPRESSION_START_INSTANCE = const [
Keyword.CONST,
Keyword.FALSE,
Keyword.NEW,
Keyword.NULL,
@ -167,6 +212,7 @@ class KeywordContributorTest extends AbstractCompletionTest {
];
static const List<Keyword> EXPRESSION_START_NO_INSTANCE = const [
Keyword.CONST,
Keyword.FALSE,
Keyword.NEW,
Keyword.NULL,
@ -539,6 +585,20 @@ class KeywordContributorTest extends AbstractCompletionTest {
assertSuggestKeywords([Keyword.THIS]);
}
test_do_break_continue() {
addTestSource('main() {do {^} while (true);}');
expect(computeFast(), isTrue);
assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
test_do_break_continue2() {
addTestSource('class A {foo() {do {^} while (true);}}');
expect(computeFast(), isTrue);
assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
test_empty() {
addTestSource('^');
expect(computeFast(), isTrue);
@ -546,6 +606,20 @@ class KeywordContributorTest extends AbstractCompletionTest {
relevance: DART_RELEVANCE_HIGH);
}
test_for_break_continue() {
addTestSource('main() {for (int x in myList) {^}}');
expect(computeFast(), isTrue);
assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
test_for_break_continue2() {
addTestSource('class A {foo() {for (int x in myList) {^}}}');
expect(computeFast(), isTrue);
assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
test_for_expression_in() {
addTestSource('main() {for (int x i^)}');
expect(computeFast(), isTrue);
@ -561,15 +635,13 @@ class KeywordContributorTest extends AbstractCompletionTest {
test_for_expression_init() {
addTestSource('main() {for (int x = i^)}');
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.FALSE, Keyword.NEW, Keyword.NULL, Keyword.TRUE]);
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
test_for_expression_init2() {
addTestSource('main() {for (int x = in^)}');
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.FALSE, Keyword.NEW, Keyword.NULL, Keyword.TRUE]);
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
test_function_async() {
@ -960,6 +1032,12 @@ class A {
expect(request.replacementLength, 3);
}
test_is_expression() {
addTestSource('main() {if (x is^)}');
expect(computeFast(), isTrue);
assertSuggestKeywords([Keyword.IS], relevance: DART_RELEVANCE_HIGH);
}
test_library() {
addTestSource('library foo;^');
expect(computeFast(), isTrue);
@ -1291,6 +1369,20 @@ class A {
assertSuggestKeywords(STMT_START_IN_SWITCH_IN_CLASS);
}
test_while_break_continue() {
addTestSource('main() {while (true) {^}}');
expect(computeFast(), isTrue);
assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
test_while_break_continue2() {
addTestSource('class A {foo() {while (true) {^}}}');
expect(computeFast(), isTrue);
assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
void _appendCompletions(
StringBuffer msg, Iterable<String> completions, Iterable<String> other) {
List<String> sorted = completions.toList();