Use the static type from the identifier element is local completions.

We always have fully reoslved unit, so usually actual types are available.

For the case when the type annotation cannot be resolved, keep the
old code that returns unresolved type string in this case. Probably
can be simplified more, e.g. remember declared types on the side instead
of passing them around just in case. Later.

R=brianwilkerson@google.com

Change-Id: Ida0b6caa90fc1408e5e7d12b762b19651cb201f6
Reviewed-on: https://dart-review.googlesource.com/55980
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index cfd7cf4..9c5afa7 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -98,7 +98,7 @@
   return new protocol.Element(kind, name, flags,
       location: location,
       parameters: parameters,
-      returnType: nameForType(returnType));
+      returnType: nameForType(id, returnType));
 }
 
 /**
@@ -141,7 +141,7 @@
       0,
       isDeprecated,
       false,
-      returnType: nameForType(returnType),
+      returnType: nameForType(id, returnType),
       element: element);
   if (classDecl != null) {
     SimpleIdentifier classId = classDecl.name;
@@ -204,33 +204,45 @@
 }
 
 /**
- * Return the name for the given [type].
+ * Return name of the type of the given [identifier], or, if it unresolved, the
+ * name of its declared [declaredType].
  */
-String nameForType(TypeAnnotation type) {
-  if (type == NO_RETURN_TYPE) {
+String nameForType(SimpleIdentifier identifier, TypeAnnotation declaredType) {
+  if (identifier == null) {
     return null;
   }
+
+  // Get the type from the identifier element.
+  DartType type;
+  Element element = identifier.staticElement;
+  if (element == null) {
+    return DYNAMIC;
+  } else if (element is FunctionTypedElement) {
+    if (element is PropertyAccessorElement && element.isSetter) {
+      return null;
+    }
+    type = element.returnType;
+  } else if (element is VariableElement) {
+    type = identifier.bestType;
+  } else {
+    return null;
+  }
+
+  // If the type is unresolved, use the declared type.
+  if (type != null && type.isUndefined) {
+    if (declaredType is TypeName) {
+      Identifier id = declaredType.name;
+      if (id != null) {
+        return id.name;
+      }
+    }
+    return DYNAMIC;
+  }
+
   if (type == null) {
     return DYNAMIC;
   }
-  if (type is TypeName) {
-    Identifier id = type.name;
-    if (id == null) {
-      return DYNAMIC;
-    }
-    String name = id.name;
-    if (name == null || name.length <= 0) {
-      return DYNAMIC;
-    }
-    TypeArgumentList typeArgs = type.typeArguments;
-    if (typeArgs != null) {
-      //TODO (danrubel) include type arguments
-    }
-    return name;
-  } else if (type is GenericFunctionType) {
-    // TODO(brianwilkerson) Implement this.
-  }
-  return DYNAMIC;
+  return type.toString();
 }
 
 //TODO(pq): fix to use getDefaultStringParameterValue()
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index fb5a912..1aa985c 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -330,7 +330,7 @@
     assertSuggestFunction('bar', 'String',
         kind: CompletionSuggestionKind.IDENTIFIER,
         relevance: DART_RELEVANCE_LOCAL_FUNCTION);
-    assertSuggestFunction('boo', 'dynamic',
+    assertSuggestFunction('boo', 'Null',
         kind: CompletionSuggestionKind.IDENTIFIER,
         relevance: DART_RELEVANCE_LOCAL_FUNCTION);
     assertNotSuggested('hasLength');
@@ -365,7 +365,7 @@
         kind: CompletionSuggestionKind.IDENTIFIER,
         relevance:
             DART_RELEVANCE_LOCAL_FUNCTION + DART_RELEVANCE_BOOST_SUBTYPE);
-    assertSuggestFunction('boo', 'dynamic',
+    assertSuggestFunction('boo', 'Null',
         kind: CompletionSuggestionKind.IDENTIFIER,
         relevance:
             DART_RELEVANCE_LOCAL_FUNCTION + DART_RELEVANCE_BOOST_SUBTYPE);
@@ -871,7 +871,7 @@
     assertSuggestMethod('a', 'X', null, relevance: DART_RELEVANCE_LOCAL_METHOD);
     assertSuggestMethod('b', 'X', 'void',
         relevance: DART_RELEVANCE_LOCAL_METHOD);
-    assertSuggestFunction('localF', null,
+    assertSuggestFunction('localF', 'Null',
         relevance: DART_RELEVANCE_LOCAL_FUNCTION);
     assertSuggestLocalVariable('f', null);
     // Don't suggest locals out of scope
@@ -2352,7 +2352,7 @@
 
     expect(replacementOffset, completionOffset);
     expect(replacementLength, 0);
-    assertSuggestLocalVariable('values', 'List');
+    assertSuggestLocalVariable('values', 'List<int>');
     assertNotSuggested('index');
   }
 
@@ -2363,7 +2363,7 @@
 
     expect(replacementOffset, completionOffset - 1);
     expect(replacementLength, 1);
-    assertSuggestLocalVariable('values', 'List');
+    assertSuggestLocalVariable('values', 'List<int>');
     assertNotSuggested('index');
   }
 
@@ -2374,7 +2374,7 @@
 
     expect(replacementOffset, completionOffset - 1);
     expect(replacementLength, 1);
-    assertSuggestLocalVariable('values', 'List');
+    assertSuggestLocalVariable('values', 'List<int>');
     assertNotSuggested('index');
   }
 
@@ -2742,7 +2742,7 @@
     }
     assertSuggestFunction('bar', 'void',
         relevance: DART_RELEVANCE_LOCAL_FUNCTION);
-    assertSuggestParameter('args', 'List');
+    assertSuggestParameter('args', 'List<dynamic>');
     assertSuggestParameter('b', 'R');
     assertNotSuggested('Object');
   }
@@ -4202,6 +4202,12 @@
     assertSuggestLocalVariable('_ab', null);
   }
 
+  test_inferredType() async {
+    addTestSource('main() { var v = 42; ^ }');
+    await computeSuggestions();
+    assertSuggestLocalVariable('v', 'int');
+  }
+
   test_prioritization_public() async {
     addTestSource('main() {var ab; var _ab; a^}');
     await computeSuggestions();