[analysis_server] Include inlay hints for type arguments in "if case"

Previously we only added the type args in constructor invocations, this changes to any named type without explicit type args.

Fixes https://github.com/Dart-Code/Dart-Code/issues/4712

Change-Id: I11a6a96bf34c7e4acff93607a922401d2f0eed83
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332960
Reviewed-by: Keerti Parthasarathy <keertip@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
diff --git a/pkg/analysis_server/lib/src/computer/computer_inlay_hint.dart b/pkg/analysis_server/lib/src/computer/computer_inlay_hint.dart
index d10f2ad..9533bdb 100644
--- a/pkg/analysis_server/lib/src/computer/computer_inlay_hint.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_inlay_hint.dart
@@ -67,16 +67,21 @@
     ));
   }
 
-  /// Adds a type hint before [node] showing a label for type arguments [types].
+  /// Adds a type hint for [node] showing a label for type arguments [types].
+  ///
+  /// Hints will be added before the node unless [suffix] is `true`.
   ///
   /// If [types] is null or empty, no hints are added.
-  void _addTypeArgumentsPrefix(
-      SyntacticEntity nodeOrToken, List<DartType>? types) {
+  void _addTypeArguments(
+    SyntacticEntity nodeOrToken,
+    List<DartType>? types, {
+    bool suffix = false,
+  }) {
     if (types == null || types.isEmpty) {
       return;
     }
 
-    final offset = nodeOrToken.offset;
+    final offset = suffix ? nodeOrToken.end : nodeOrToken.offset;
     final position = toPosition(_lineInfo.getLocation(offset));
     final labelParts = <InlayHintLabelPart>[];
     _appendTypeArgumentParts(labelParts, types);
@@ -211,7 +216,8 @@
   }
 
   /// Adds a Type hint for type arguments of [type] (if it has type arguments).
-  void _maybeAddTypeArguments(Token token, DartType? type) {
+  void _maybeAddTypeArguments(Token token, DartType? type,
+      {bool suffix = false}) {
     if (type is! ParameterizedType) {
       return;
     }
@@ -221,7 +227,7 @@
       return;
     }
 
-    _addTypeArgumentsPrefix(token, typeArgumentTypes);
+    _addTypeArguments(token, typeArgumentTypes, suffix: suffix);
   }
 }
 
@@ -286,20 +292,6 @@
   }
 
   @override
-  void visitInstanceCreationExpression(InstanceCreationExpression node) {
-    super.visitInstanceCreationExpression(node);
-
-    // Has explicit type arguments.
-    if (node.constructorName.type.typeArguments != null) {
-      return;
-    }
-
-    final token = node.argumentList.leftParenthesis;
-    final type = node.staticType;
-    _computer._maybeAddTypeArguments(token, type);
-  }
-
-  @override
   void visitInvocationExpression(InvocationExpression node) {
     super.visitInvocationExpression(node);
 
@@ -308,7 +300,7 @@
       return;
     }
 
-    _computer._addTypeArgumentsPrefix(
+    _computer._addTypeArguments(
         node.argumentList.leftParenthesis, node.typeArgumentTypes);
   }
 
@@ -342,6 +334,20 @@
   }
 
   @override
+  void visitNamedType(NamedType node) {
+    super.visitNamedType(node);
+
+    // Has explicit type arguments.
+    if (node.typeArguments != null) {
+      return;
+    }
+
+    final token = node.endToken;
+    final type = node.type;
+    _computer._maybeAddTypeArguments(token, type, suffix: true);
+  }
+
+  @override
   void visitSetOrMapLiteral(SetOrMapLiteral node) {
     super.visitSetOrMapLiteral(node);
 
diff --git a/pkg/analysis_server/test/lsp/inlay_hint_test.dart b/pkg/analysis_server/test/lsp/inlay_hint_test.dart
index da38577..3e18218 100644
--- a/pkg/analysis_server/test/lsp/inlay_hint_test.dart
+++ b/pkg/analysis_server/test/lsp/inlay_hint_test.dart
@@ -490,6 +490,30 @@
     await _expectHints(content, expected);
   }
 
+  Future<void> test_patterns_ifCase_typeArguments() async {
+    final content = '''
+class Box<T> {
+  final T value;
+  Box(this.value);
+}
+
+void f(Box<List<String>> a) {
+  if (a case Box(value: List(:final int length))) {}
+}
+''';
+    final expected = '''
+class Box<T> {
+  final T value;
+  Box(this.value);
+}
+
+void f(Box<List<String>> a) {
+  if (a case Box(Type:<List<String>>)(value: List(Type:<String>)(:final int length))) {}
+}
+''';
+    await _expectHints(content, expected);
+  }
+
   Future<void> test_patterns_switchExpression() async {
     final content = '''
 void f() {