@@ -2867,8 +2867,12 @@ public void visitStaticMethodCallExpression(final StaticMethodCallExpression cal
2867
2867
for (Receiver <String > currentReceiver : receivers ) {
2868
2868
mn = findMethod (currentReceiver .getType (), name , args );
2869
2869
if (!mn .isEmpty ()) {
2870
- if (mn .size () == 1 )
2870
+ if (mn .size () == 1 ) {
2871
+ // GRECLIPSE add -- GROOVY-8961, GROOVY-9734, GROOVY-9915
2872
+ resolvePlaceholdersFromImplicitTypeHints (args , argumentList , mn .get (0 ));
2873
+ // GRECLIPSE end
2871
2874
typeCheckMethodsWithGenericsOrFail (currentReceiver .getType (), args , mn .get (0 ), call );
2875
+ }
2872
2876
chosenReceiver = currentReceiver ;
2873
2877
break ;
2874
2878
}
@@ -3768,36 +3772,7 @@ public void visitMethodCallExpression(MethodCallExpression call) {
3768
3772
}
3769
3773
}
3770
3774
// GRECLIPSE add -- GROOVY-8961, GROOVY-9734
3771
- for (int i = 0 , n = args .length ; i < n ; i += 1 ) {
3772
- Expression a = argumentList .getExpression (i ); ClassNode at = args [i ];
3773
- if (a instanceof MethodCallExpression && !((MethodCallExpression ) a ).isUsingGenerics () && isUsingUncheckedGenerics (at )) {
3774
- // try to resolve unresolved placeholders in argument type using parameter type
3775
-
3776
- MethodNode aNode = a .getNodeMetaData (StaticTypesMarker .DIRECT_METHOD_CALL_TARGET );
3777
- if (aNode == null || aNode .getGenericsTypes () == null ) continue ;
3778
-
3779
- int np = directMethodCallCandidate .getParameters ().length ;
3780
- Parameter p = directMethodCallCandidate .getParameters ()[Math .min (i , np )];
3781
- ClassNode pt = getType (p ); if (i >= (np - 1 ) && pt .isArray () && !at .isArray ()) pt = pt .getComponentType ();
3782
-
3783
- Map <GenericsTypeName , GenericsType > source = extractPlaceholders (at );
3784
- Map <GenericsTypeName , GenericsType > target = extractPlaceholders (pt );
3785
- Map <GenericsTypeName , GenericsType > linked = new HashMap <>();
3786
-
3787
- // connect E:T from source to E:Type from target
3788
- for (GenericsType placeholder : aNode .getGenericsTypes ()) {
3789
- for (Map .Entry <GenericsTypeName , GenericsType > e : source .entrySet ()) {
3790
- if (e .getValue () == placeholder ) {
3791
- Optional .ofNullable (target .get (e .getKey ()))
3792
- .filter (gt -> isAssignableTo (gt .getType (), placeholder .getType ()))
3793
- .ifPresent (gt -> linked .put (new GenericsTypeName (placeholder .getName ()), gt ));
3794
- break ;
3795
- }
3796
- }
3797
- }
3798
- args [i ] = applyGenericsContext (linked , at );
3799
- }
3800
- }
3775
+ resolvePlaceholdersFromImplicitTypeHints (args , argumentList , directMethodCallCandidate );
3801
3776
// GRECLIPSE end
3802
3777
if (typeCheckMethodsWithGenericsOrFail (chosenReceiver .getType (), args , directMethodCallCandidate , call )) {
3803
3778
returnType = adjustWithTraits (directMethodCallCandidate , chosenReceiver .getType (), args , returnType );
@@ -5575,6 +5550,53 @@ private static void resolvePlaceholdersFromExplicitTypeHints(final MethodNode me
5575
5550
}
5576
5551
}
5577
5552
5553
+ /**
5554
+ * Given method call like "m(Collections.emptyList())", the type of the call
5555
+ * argument is {@code List<T>} without explicit type arguments. Knowning the
5556
+ * method target of "m", {@code T} could be resolved.
5557
+ */
5558
+ private static void resolvePlaceholdersFromImplicitTypeHints (final ClassNode [] actuals , final ArgumentListExpression argumentList , final MethodNode inferredMethod ) {
5559
+ for (int i = 0 , n = actuals .length ; i < n ; i += 1 ) {
5560
+ // check for method call with known target
5561
+ Expression a = argumentList .getExpression (i );
5562
+ if (!(a instanceof MethodCallExpression )) continue ;
5563
+ if (((MethodCallExpression ) a ).isUsingGenerics ()) continue ;
5564
+ MethodNode aNode = a .getNodeMetaData (StaticTypesMarker .DIRECT_METHOD_CALL_TARGET );
5565
+ if (aNode == null || aNode .getGenericsTypes () == null ) continue ;
5566
+
5567
+ // and unknown generics
5568
+ ClassNode at = actuals [i ];
5569
+ if (!GenericsUtils .hasUnresolvedGenerics (at )) continue ;
5570
+
5571
+ int np = inferredMethod .getParameters ().length ;
5572
+ Parameter p = inferredMethod .getParameters ()[Math .min (i , np - 1 )];
5573
+
5574
+ ClassNode pt = p .getOriginType ();
5575
+ if (i >= (np - 1 ) && pt .isArray () && !at .isArray ()) pt = pt .getComponentType ();
5576
+
5577
+ // try to resolve placeholder(s) in argument type using parameter type
5578
+
5579
+ Map <GenericsTypeName , GenericsType > linked = new HashMap <>();
5580
+ Map <GenericsTypeName , GenericsType > source = GenericsUtils .extractPlaceholders (at );
5581
+ Map <GenericsTypeName , GenericsType > target = GenericsUtils .extractPlaceholders (pt );
5582
+
5583
+ // connect E:T from source to E:Type from target
5584
+ for (GenericsType placeholder : aNode .getGenericsTypes ()) {
5585
+ for (Map .Entry <GenericsTypeName , GenericsType > e : source .entrySet ()) {
5586
+ if (e .getValue () == placeholder ) {
5587
+ Optional .ofNullable (target .get (e .getKey ()))
5588
+ // skip "f(g())" for "f(T<String>)" and "<U extends Number> U g()"
5589
+ .filter (gt -> isAssignableTo (gt .getType (), placeholder .getType ()))
5590
+ .ifPresent (gt -> linked .put (new GenericsTypeName (placeholder .getName ()), gt ));
5591
+ break ;
5592
+ }
5593
+ }
5594
+ }
5595
+
5596
+ actuals [i ] = applyGenericsContext (linked , at );
5597
+ }
5598
+ }
5599
+
5578
5600
private static void extractGenericsConnectionsForSuperClassAndInterfaces (final Map <GenericsTypeName , GenericsType > resolvedPlaceholders , final Map <GenericsTypeName , GenericsType > connections ) {
5579
5601
for (GenericsType value : new HashSet <GenericsType >(connections .values ())) {
5580
5602
if (!value .isPlaceholder () && !value .isWildcard ()) {
0 commit comments