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>
diff --git a/pkg/analysis_server/lib/src/domains/execution/completion.dart b/pkg/analysis_server/lib/src/domains/execution/completion.dart
index c2ac622..df93f288 100644
--- a/pkg/analysis_server/lib/src/domains/execution/completion.dart
+++ b/pkg/analysis_server/lib/src/domains/execution/completion.dart
@@ -57,6 +57,7 @@
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 @@
}
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 @@
} 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);
}
- // TODO(scheglov) support method/function/class
+ _appendLocals(node.parent);
+ }
+
+ void _appendParameters(FormalParameterList parameters) {
+ if (parameters != null) {
+ for (var parameter in parameters.parameters) {
+ VariableElement element = parameter.element;
+ locals[element.name] ??= element;
+ }
+ }
}
}
diff --git a/pkg/analysis_server/test/src/domains/execution/completion_test.dart b/pkg/analysis_server/test/src/domains/execution/completion_test.dart
index 8ca1d93..986dc65 100644
--- a/pkg/analysis_server/test/src/domains/execution/completion_test.dart
+++ b/pkg/analysis_server/test/src/domains/execution/completion_test.dart
@@ -33,14 +33,21 @@
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');
}
- failedCompletion('expected $completion');
+ }
+
+ void assertSuggested(String completion, {String returnType}) {
+ CompletionSuggestion suggestion = getSuggest(completion);
+ if (suggestion == null) {
+ failedCompletion('expected $completion');
+ }
+ if (returnType != null) {
+ expect(suggestion.returnType, returnType);
+ }
}
Future<void> computeCompletion(
@@ -78,6 +85,16 @@
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 @@
}
''');
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 @@
}
''');
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');
}
}