mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
improve keyword suggestions - fixes #24016
R=brianwilkerson@google.com Review URL: https://codereview.chromium.org//1303233008 .
This commit is contained in:
parent
7f0916d16e
commit
bd95b13b90
4 changed files with 156 additions and 18 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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+=="],
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue