Runtime completion support for constructors, for loops, and function expressions.

R=brianwilkerson@google.com

Change-Id: I3d33841b9386b6c9fb0e0f74946ca6fe9449581a
Reviewed-on: https://dart-review.googlesource.com/55911
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@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 646f9b6..3ccff5e 100644
--- a/pkg/analysis_server/lib/src/domains/execution/completion.dart
+++ b/pkg/analysis_server/lib/src/domains/execution/completion.dart
@@ -160,10 +160,7 @@
           break;
         }
         if (statement is VariableDeclarationStatement) {
-          for (var variable in statement.variables.variables) {
-            VariableElement element = variable.element;
-            locals[element.name] ??= element;
-          }
+          _appendVariables(statement.variables);
         }
       }
     } else if (node is ClassDeclaration) {
@@ -171,8 +168,19 @@
       return;
     } else if (node is CompilationUnit) {
       return;
+    } else if (node is ConstructorDeclaration) {
+      _appendParameters(node.parameters);
     } else if (node is FunctionDeclaration) {
       _appendParameters(node.functionExpression.parameters);
+    } else if (node is FunctionExpression) {
+      _appendParameters(node.parameters);
+    } else if (node is ForEachStatement) {
+      LocalVariableElement element = node.loopVariable?.element;
+      if (element != null) {
+        locals[element.name] ??= element;
+      }
+    } else if (node is ForStatement) {
+      _appendVariables(node.variables);
     } else if (node is MethodDeclaration) {
       _appendParameters(node.parameters);
     }
@@ -187,4 +195,13 @@
       }
     }
   }
+
+  void _appendVariables(VariableDeclarationList variables) {
+    if (variables != null) {
+      for (var variable in variables.variables) {
+        VariableElement element = variable.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 986dc65..cd48659 100644
--- a/pkg/analysis_server/test/src/domains/execution/completion_test.dart
+++ b/pkg/analysis_server/test/src/domains/execution/completion_test.dart
@@ -126,7 +126,7 @@
     assertSuggested('toUpperCase');
   }
 
-  test_locals_nested() async {
+  test_locals_block_nested() async {
     addContextFile(r'''
 void main() {
   var a = 0;
@@ -146,6 +146,47 @@
     assertNotSuggested('c');
   }
 
+  test_locals_for() async {
+    addContextFile(r'''
+void main(List<int> intItems, List<double> doubleItems) {
+  for (var a = 0, b = 0.0; a < 5; a++) {
+    // context line
+  }
+}
+''');
+    await computeCompletion('^');
+    assertSuggested('a', returnType: 'int');
+    assertSuggested('b', returnType: 'double');
+  }
+
+  test_locals_forEach() async {
+    addContextFile(r'''
+void main(List<int> intItems, List<double> doubleItems) {
+  for (var a in intItems) {
+    for (var b in doubleItems) {
+      // context line
+    }
+  }
+}sosol
+''');
+    await computeCompletion('^');
+    assertSuggested('a', returnType: 'int');
+    assertSuggested('b', returnType: 'double');
+  }
+
+  test_parameters_constructor() async {
+    addContextFile(r'''
+class C {
+  C(int a, double b) {
+    // context line
+  }
+}
+''');
+    await computeCompletion('^');
+    assertSuggested('a', returnType: 'int');
+    assertSuggested('b', returnType: 'double');
+  }
+
   test_parameters_function() async {
     addContextFile(r'''
 void main(int a, double b) {
@@ -185,6 +226,21 @@
     assertSuggested('c', returnType: 'bool');
   }
 
+  test_parameters_functionExpression() async {
+    addContextFile(r'''
+void main(List<int> intItems, List<double> doubleItems) {
+  intItems.forEach((a) {
+    doubleItems.forEach((b) {
+      // context line
+    });
+  });
+}
+''');
+    await computeCompletion('^');
+    assertSuggested('a', returnType: 'int');
+    assertSuggested('b', returnType: 'double');
+  }
+
   test_parameters_method() async {
     addContextFile(r'''
 class C {