Tests for completion with nested blocks, functions, and methods.

R=brianwilkerson@google.com

Change-Id: I050aaa2f80a3374fd92587a0b8461bc170078bd8
Reviewed-on: https://dart-review.googlesource.com/55903
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2018-05-18 17:43:38 +00:00 committed by commit-bot@chromium.org
parent 353ddbaea1
commit 7a90ed9b88
2 changed files with 132 additions and 29 deletions

View file

@ -57,6 +57,7 @@ class RuntimeCompletionComputer {
var contextDir = pathContext.dirname(contextFile);
var targetPath = pathContext.join(contextDir, '_runtimeCompletion.dart');
// TODO(scheglov) Use variables.
await _initContext();
String baseTargetCode = r'''
@ -156,23 +157,15 @@ class _Context {
}
void _appendLocals(AstNode node) {
void appendParameters(FormalParameterList parameters) {
if (parameters != null) {
for (var parameter in parameters.parameters) {
VariableElement element = parameter.element;
locals[element.name] ??= element;
}
}
}
if (node is Block) {
for (var statement in node.statements) {
if (statement.offset > contextOffset) {
break;
}
if (statement is VariableDeclarationStatement) {
for (var variable in statement.variables.variables) {
VariableElement element = variable.element;
if (element.nameOffset < contextOffset) {
locals[element.name] ??= element;
}
locals[element.name] ??= element;
}
}
}
@ -182,14 +175,19 @@ class _Context {
} else if (node is CompilationUnit) {
return;
} else if (node is FunctionDeclaration) {
// TODO(scheglov) test
appendParameters(node.functionExpression.parameters);
_appendParameters(node.functionExpression.parameters);
} else if (node is MethodDeclaration) {
// TODO(scheglov) test
appendParameters(node.parameters);
} else {
_appendLocals(node.parent);
_appendParameters(node.parameters);
}
_appendLocals(node.parent);
}
void _appendParameters(FormalParameterList parameters) {
if (parameters != null) {
for (var parameter in parameters.parameters) {
VariableElement element = parameter.element;
locals[element.name] ??= element;
}
}
// TODO(scheglov) support method/function/class
}
}

View file

@ -33,14 +33,21 @@ class RuntimeCompletionComputerTest extends AbstractContextTest {
reason: "Not found '// context line'.");
}
void assertSuggest(String completion) {
expect(result.suggestions, isNotNull);
for (var suggestion in result.suggestions) {
if (suggestion.completion == completion) {
return;
}
void assertNotSuggested(String completion) {
CompletionSuggestion suggestion = getSuggest(completion);
if (suggestion != null) {
failedCompletion('unexpected $completion');
}
}
void assertSuggested(String completion, {String returnType}) {
CompletionSuggestion suggestion = getSuggest(completion);
if (suggestion == null) {
failedCompletion('expected $completion');
}
if (returnType != null) {
expect(suggestion.returnType, returnType);
}
failedCompletion('expected $completion');
}
Future<void> computeCompletion(
@ -78,6 +85,16 @@ class RuntimeCompletionComputerTest extends AbstractContextTest {
fail(sb.toString());
}
CompletionSuggestion getSuggest(String completion) {
expect(result.suggestions, isNotNull);
for (var suggestion in result.suggestions) {
if (suggestion.completion == completion) {
return suggestion;
}
}
return null;
}
test_locals_block() async {
addContextFile(r'''
class A {
@ -90,12 +107,12 @@ void contextFunction() {
}
''');
await computeCompletion('a.^');
assertSuggest('foo');
assertSuggested('foo');
// There was an issue with cleaning up
// Check that the second time it works too.
await computeCompletion('a.^');
assertSuggest('foo');
assertSuggested('foo');
}
test_locals_block_codeWithClosure() async {
@ -106,6 +123,94 @@ main() {
}
''');
await computeCompletion('items.forEach((e) => e.^)');
assertSuggest('toUpperCase');
assertSuggested('toUpperCase');
}
test_locals_nested() async {
addContextFile(r'''
void main() {
var a = 0;
var b = 0.0;
{
var a = '';
// context line
}
var c = 0;
}
''');
await computeCompletion('^');
assertSuggested('a', returnType: 'String');
assertSuggested('b', returnType: 'double');
// "c" is defined after the context offset, so is not visible.
assertNotSuggested('c');
}
test_parameters_function() async {
addContextFile(r'''
void main(int a, double b) {
// context line
}
''');
await computeCompletion('^');
assertSuggested('a', returnType: 'int');
assertSuggested('b', returnType: 'double');
}
test_parameters_function_locals() async {
addContextFile(r'''
void main(int a, int b) {
String a;
double c;
// context line
}
''');
await computeCompletion('^');
assertSuggested('a', returnType: 'String');
assertSuggested('b', returnType: 'int');
assertSuggested('c', returnType: 'double');
}
test_parameters_function_nested() async {
addContextFile(r'''
void foo(int a, double b) {
void bar(String a, bool c) {
// context line
}
}
''');
await computeCompletion('^');
assertSuggested('a', returnType: 'String');
assertSuggested('b', returnType: 'double');
assertSuggested('c', returnType: 'bool');
}
test_parameters_method() async {
addContextFile(r'''
class C {
void main(int a, double b) {
// context line
}
}
''');
await computeCompletion('^');
assertSuggested('a', returnType: 'int');
assertSuggested('b', returnType: 'double');
}
test_parameters_method_locals() async {
addContextFile(r'''
class C {
void main(int a, int b) {
String a;
double c;
// context line
}
}
''');
await computeCompletion('^');
assertSuggested('a', returnType: 'String');
assertSuggested('b', returnType: 'int');
assertSuggested('c', returnType: 'double');
}
}