3434import org .jetbrains .annotations .Nullable ;
3535
3636import java .util .*;
37+ import java .util .stream .Collectors ;
3738import java .util .stream .Stream ;
3839
3940import static com .intellij .plugins .haxe .lang .lexer .HaxeTokenTypeSets .ONLY_COMMENTS ;
4041import static com .intellij .plugins .haxe .lang .lexer .HaxeTokenTypes .KUNTYPED ;
4142import static com .intellij .plugins .haxe .lang .psi .impl .HaxeReferenceImpl .getLiteralClassName ;
4243import static com .intellij .plugins .haxe .lang .psi .impl .HaxeReferenceImpl .tryToFindTypeFromCallExpression ;
44+ import static com .intellij .plugins .haxe .lang .psi .impl .HaxeReferenceUtil .isStaticExtension ;
45+ import static com .intellij .plugins .haxe .lang .psi .impl .HaxeReferenceUtil .wrapTypeInClassOrEnum ;
4346import static com .intellij .plugins .haxe .model .evaluator .HaxeExpressionUsageUtil .searchReferencesForTypeParameters ;
4447import static com .intellij .plugins .haxe .model .evaluator .HaxeExpressionUsageUtil .tryToFindTypeFromUsage ;
4548import static com .intellij .plugins .haxe .model .evaluator .callexpression .HaxeCallExpressionUtil .isBindCall ;
@@ -301,7 +304,7 @@ static ResultHolder handleReferenceExpression( HaxeExpressionEvaluatorContext co
301304 SpecificHaxeClassReference classType = typeHolder .getClassType ();
302305 if (classType != null ) {
303306 HaxeClass haxeClass = classType .getHaxeClass ();
304- if (haxeClass != null ) typeHolder = wrapTypeInClassOrEnum (element , haxeClass , haxeClass . getModel () );
307+ if (haxeClass != null ) typeHolder = wrapTypeInClassOrEnum (element , haxeClass );
305308 }
306309 }
307310 }
@@ -331,7 +334,7 @@ static ResultHolder handleReferenceExpression( HaxeExpressionEvaluatorContext co
331334 if (expression .isPureClassReferenceOf (haxeClass )) {
332335 // make sure its not an import statement
333336 if (PsiTreeUtil .getParentOfType (expression , HaxeImportStatement .class ) == null ) {
334- typeHolder = wrapTypeInClassOrEnum (element , haxeClass , model );
337+ typeHolder = wrapTypeInClassOrEnum (element , haxeClass );
335338 }
336339 }
337340 }
@@ -394,6 +397,25 @@ else if (subelement instanceof HaxeMethod haxeMethod) {
394397
395398 SpecificFunctionReference type = haxeMethod .getModel ().getFunctionType (isFromCallExpression ? localResolver : localResolver .withoutAssignHint ());
396399 if (!isFromCallExpression ) {
400+ if ( reference instanceof HaxeReferenceExpression referenceExpression ) {
401+ // if this is a reference to an extension method we need to bind the callie type
402+ if (isStaticExtension (referenceExpression )) {
403+ List <HaxeArgument > argumentsToKeep = type .getArguments ();
404+ HaxeGenericResolver bindResolver = null ;
405+ // if this is from a method we might have typeParameters and need to "bind" these if they are present in the callie
406+ if (type .method != null ) {
407+ List <SpecificTypeReference > params = argumentsToKeep .stream ().map (HaxeArgument ::getType ).map (ResultHolder ::getType ).collect (Collectors .toList ());
408+ params .removeFirst ();
409+ SpecificTypeReference callieType = tryToFindPreviousTypeInChainForExtensionMethods (element .getFirstChild ());
410+ params .addFirst (callieType );
411+ HaxeCallExpressionContext tmpContext = HaxeCallExpressionUtil .createContextForMethodCall (params , type .method , null );
412+ HaxeCallExpressionEvaluation evaluate = tmpContext .evaluate ();
413+ bindResolver = evaluate .getCallExpressionResolver ();
414+ }
415+ argumentsToKeep .removeFirst (); // remove first argument as this should be the callie
416+ type = type .performMethodBind (argumentsToKeep , bindResolver );
417+ }
418+ }
397419 // expression is referring to the method not calling it.
398420 // assign hint should be used for substituting parameters instead of being used as return type
399421 type = resolver .substituteTypeParamsWithAssignHintTypes (type );
@@ -484,17 +506,21 @@ else if (typeHolder == null || typeHolder.isUnknown()) {
484506 //return SpecificTypeReference.getDynamic(element).createHolder();
485507 }
486508
487- private static ResultHolder wrapTypeInClassOrEnum (HaxeReferenceExpression element , HaxeClass haxeClass , HaxeClassModel model ) {
488- ResultHolder typeHolder ;
489- // wrap in Class<> or Enum<>
490- SpecificHaxeClassReference originalClass = SpecificHaxeClassReference .withoutGenerics (model .getReference ());
491- SpecificHaxeClassReference wrappedClass =
492- SpecificHaxeClassReference .getStdClass (haxeClass .isEnum () ? ENUM : CLASS , element ,
493- new ResultHolder []{new ResultHolder (originalClass )});
494- typeHolder = wrappedClass .createHolder ();
495- return typeHolder ;
509+ private static SpecificTypeReference tryToFindPreviousTypeInChainForExtensionMethods (PsiElement firstChild ) {
510+ ResultHolder result = evaluateWithRecursionGuard (firstChild ).result ;
511+ if (result == null ) return createUnknown (firstChild ).getType ();
512+ // check if extension method is on a pure references and if so wrap it in class/enum
513+ if (result .getType () instanceof SpecificHaxeClassReference classReference ) {
514+ String className = classReference .getClassName ();
515+ if (className != null &&firstChild .textMatches (className )) {
516+ HaxeClass haxeClass = classReference .getHaxeClass ();
517+ if (haxeClass != null ) return wrapTypeInClassOrEnum (firstChild , haxeClass ).getType ();
518+ }
519+ }
520+ return result .getType ();
496521 }
497522
523+
498524 private static boolean isReificationExpression (HaxeReferenceExpression element ) {
499525 return false ;
500526 }
@@ -1467,7 +1493,11 @@ static ResultHolder handleCallExpression(
14671493 SpecificTypeReference assignHintType = assignHint == null ? null : assignHint .getType ();
14681494 HaxeCallExpressionContext callExpressionContext = HaxeCallExpressionUtil .createContextForMethodCall (callExpression , assignHintType , methodModel .getMethod ());
14691495 HaxeCallExpressionEvaluation evaluate = callExpressionContext .evaluate ();
1470- functionType = evaluate .getFunctionType (methodModel );
1496+ if (evaluate .isValid ()) {
1497+ functionType = evaluate .getFunctionType (methodModel );
1498+ }else {
1499+ functionType = createUnknown (callExpression ).getType ();
1500+ }
14711501 }else {
14721502 SpecificTypeReference callieRef = tryGetCallieType (callExpression );
14731503 if (callieRef instanceof SpecificHaxeClassReference classReference && !classReference .isUnknown ()) {
@@ -1639,6 +1669,8 @@ static ResultHolder handleCallExpression(
16391669 private static ResultHolder tryHandleFunctionBind (SpecificFunctionReference functionReference , HaxeCallExpression callExpression ) {
16401670 List <HaxeArgument > arguments = functionReference .getArguments ();
16411671 List <HaxeArgument > argumentsToKeep = new ArrayList <>();
1672+ List <SpecificTypeReference > tmParamList = new ArrayList <>();
1673+ boolean canHaveTypeParameters = functionReference .method != null ;
16421674
16431675 HaxeCallExpressionList expressionList = callExpression .getExpressionList ();
16441676 if (expressionList == null ) {
@@ -1648,9 +1680,10 @@ private static ResultHolder tryHandleFunctionBind(SpecificFunctionReference func
16481680 argumentsToKeep .add (argument );
16491681 }
16501682 }
1651- return functionReference .performMethodBind (argumentsToKeep ).createHolder ();
1683+ return functionReference .performMethodBind (argumentsToKeep , null ).createHolder ();
16521684 } else {
16531685 List <HaxeExpression > expressions = expressionList .getExpressionList ();
1686+
16541687 for (int i = 0 ; i < arguments .size (); i ++) {
16551688 HaxeExpression expr = expressions .size () > i ? expressions .get (i ) : null ;
16561689 HaxeArgument argument = arguments .get (i );
@@ -1661,12 +1694,25 @@ private static ResultHolder tryHandleFunctionBind(SpecificFunctionReference func
16611694 if (expr == null ) {
16621695 if (!optional ) {
16631696 argumentsToKeep .add (argument );
1697+ if (canHaveTypeParameters ) tmParamList .add (argument .getType ().getType ());
16641698 }
16651699 } else if (expr .textMatches ("_" )) {
16661700 argumentsToKeep .add (argument );
1701+ if (canHaveTypeParameters ) tmParamList .add (argument .getType ().getType ());
1702+ }else {
1703+ if (canHaveTypeParameters ) {
1704+ ResultHolder expressionType = evaluateWithRecursionGuard (expr ).result ;
1705+ tmParamList .add (expressionType .getType ());
1706+ }
16671707 }
16681708 }
1669- return functionReference .performMethodBind (argumentsToKeep ).createHolder ();
1709+ if (canHaveTypeParameters ) {
1710+ HaxeCallExpressionContext context = HaxeCallExpressionUtil .createContextForMethodCall (tmParamList , functionReference .method , null );
1711+ HaxeCallExpressionEvaluation evaluate = context .evaluate ();
1712+ HaxeGenericResolver callExpressionResolver = evaluate .getCallExpressionResolver ();
1713+ return functionReference .performMethodBind (argumentsToKeep , callExpressionResolver ).createHolder ();
1714+ }
1715+ return functionReference .performMethodBind (argumentsToKeep , null ).createHolder ();
16701716 }
16711717 }
16721718
0 commit comments