Skip to content

Commit 4ce3062

Browse files
committed
Tweaking capture variable type resolve to hopefully better handle arrays (#1233)
1 parent 76cc877 commit 4ce3062

File tree

6 files changed

+111
-12
lines changed

6 files changed

+111
-12
lines changed

src/main/java/com/intellij/plugins/haxe/lang/psi/HaxeResolver.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,7 +1542,7 @@ private static List<PsiElement> tryResolveExtractedValue(HaxeReference reference
15421542
boolean checkParent = true;
15431543

15441544
HaxeSwitchStatement switchStatement = PsiTreeUtil.getParentOfType(reference, HaxeSwitchStatement.class);
1545-
PsiElement pathElement = buildExtractVarLiteralPath(parent, checkParent, objectPath, switchStatement);
1545+
PsiElement pathElement = buildExtractVarPath(parent, checkParent, objectPath, switchStatement);
15461546

15471547
HaxeNamedComponent lastElement = null;
15481548
Collections.reverse(objectPath);
@@ -1599,7 +1599,7 @@ private static List<PsiElement> tryResolveExtractedValue(HaxeReference reference
15991599
return null;
16001600
}
16011601

1602-
private static @Nullable PsiElement buildExtractVarLiteralPath(PsiElement extractedValue, boolean checkParent, Stack<Object> objectPath, HaxeSwitchStatement switchStatement) {
1602+
public static @Nullable PsiElement buildExtractVarPath(PsiElement extractedValue, boolean checkParent, Stack<Object> objectPath, HaxeSwitchStatement switchStatement) {
16031603
PsiElement pastParent = extractedValue;
16041604
PsiElement valueParent = extractedValue.getParent();
16051605
PsiElement pathElement = null;
@@ -1609,6 +1609,10 @@ private static List<PsiElement> tryResolveExtractedValue(HaxeReference reference
16091609
if (valueParent instanceof HaxeEnumObjectLiteralElement objectLiteralElement) {
16101610
objectPath.add(extractObjectLiteralName(objectLiteralElement));
16111611

1612+
} else if (valueParent instanceof HaxeEnumExtractArrayLiteral arrayLiteral) {
1613+
List<PsiElement> caseExpressionList = Arrays.asList(arrayLiteral.getChildren());
1614+
objectPath.add(caseExpressionList.indexOf(pastParent));
1615+
16121616
} else if (valueParent instanceof HaxeSwitchCaseExprArray caseExprArray) {
16131617
List<PsiElement> caseExpressionList = Arrays.asList(caseExprArray.getChildren());
16141618
objectPath.add(caseExpressionList.indexOf(pastParent));

src/main/java/com/intellij/plugins/haxe/lang/psi/impl/HaxeStringLiteralImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222

2323
import com.intellij.lang.ASTNode;
2424
import com.intellij.openapi.util.TextRange;
25+
import com.intellij.plugins.haxe.lang.psi.HaxeLiteralExpression;
2526
import com.intellij.psi.*;
2627
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
2728
import com.intellij.psi.impl.source.tree.LeafElement;
2829
import org.jetbrains.annotations.NotNull;
2930
import org.jetbrains.annotations.Nullable;
3031

31-
abstract public class HaxeStringLiteralImpl extends HaxeReferenceImpl implements PsiLanguageInjectionHost, PsiLiteralValue {
32+
abstract public class HaxeStringLiteralImpl extends HaxeReferenceImpl implements PsiLanguageInjectionHost, PsiLiteralValue, HaxeLiteralExpression {
3233

3334
public HaxeStringLiteralImpl(ASTNode node) {
3435
super(node);

src/main/java/com/intellij/plugins/haxe/model/evaluator/HaxeExpressionEvaluator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ static ResultHolder _handle(@Nullable final PsiElement element,
241241
}
242242

243243
if (element instanceof HaxeEnumExtractedValueReference extractedValue) {
244-
return handleEnumExtractedValue(extractedValue, resolver);
244+
return handleExtractedValue(extractedValue, resolver);
245245
}
246246

247247

src/main/java/com/intellij/plugins/haxe/model/evaluator/HaxeExpressionEvaluatorHandlers.java

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
import static com.intellij.plugins.haxe.lang.lexer.HaxeTokenTypeSets.ONLY_COMMENTS;
4141
import static com.intellij.plugins.haxe.lang.lexer.HaxeTokenTypes.KUNTYPED;
42+
import static com.intellij.plugins.haxe.lang.psi.HaxeResolver.buildExtractVarPath;
4243
import static com.intellij.plugins.haxe.lang.psi.impl.HaxeReferenceImpl.getLiteralClassName;
4344
import static com.intellij.plugins.haxe.lang.psi.impl.HaxeReferenceImpl.tryToFindTypeFromCallExpression;
4445
import static com.intellij.plugins.haxe.lang.psi.impl.HaxeReferenceUtil.isStaticExtension;
@@ -856,28 +857,88 @@ public void run() {
856857
}
857858

858859

859-
static ResultHolder handleEnumExtractedValue(@NotNull HaxeEnumExtractedValueReference extractedValue, @NotNull HaxeGenericResolver resolver) {
860-
HaxeExtractorMatchExpression matchExpression = PsiTreeUtil.getParentOfType(extractedValue, HaxeExtractorMatchExpression.class, true, HaxeEnumArgumentExtractor.class);
860+
static ResultHolder handleExtractedValue(@NotNull HaxeEnumExtractedValueReference extractedValueRef, @NotNull HaxeGenericResolver resolver) {
861+
HaxeExtractorMatchExpression matchExpression = PsiTreeUtil.getParentOfType(extractedValueRef, HaxeExtractorMatchExpression.class, true, HaxeEnumArgumentExtractor.class);
861862
if (matchExpression != null) {
862863
HaxeSwitchCaseExpr match = matchExpression.getMatch();
863-
if (PsiTreeUtil.isAncestor(match, extractedValue, false)) {
864+
if (PsiTreeUtil.isAncestor(match, extractedValueRef, false)) {
864865
return evaluate(matchExpression.getExtractorExpression(), resolver).result;
865866
}
866867
}
867868

868-
HaxeEnumArgumentExtractor extractor = PsiTreeUtil.getParentOfType(extractedValue, HaxeEnumArgumentExtractor.class, true, HaxeEnumArgumentExtractor.class);
869+
HaxeEnumArgumentExtractor extractor = PsiTreeUtil.getParentOfType(extractedValueRef, HaxeEnumArgumentExtractor.class, true, HaxeEnumArgumentExtractor.class);
869870
if (extractor != null) {
870871
HaxeEnumExtractorModel extractorModel = (HaxeEnumExtractorModel)extractor.getModel();
871-
return extractorModel.resolveExtractedValueType(extractedValue);
872+
return extractorModel.resolveExtractedValueType(extractedValueRef);
872873
}
873874

874-
PsiElement resolve = extractedValue.resolve();
875+
PsiElement resolve = extractedValueRef.resolve();
875876
if(resolve != null) {
876-
return evaluate(resolve).result;
877+
878+
ResultHolder result = evaluate(resolve).result;
879+
880+
if (extractedValueRef.getParent() instanceof HaxeEnumExtractedValue extractedValue) {
881+
//TODO: mlo - We should probably try to redo how switch extractors are parsed in the BNF
882+
// to get more consistency between ExprArray and ArrayLiteral (we might not need both)
883+
if (extractedValue.getParent() instanceof HaxeEnumExtractArrayLiteral
884+
|| extractedValue.getParent() instanceof HaxeSwitchCaseExprArray) {
885+
886+
Stack<Object> objectPath = new Stack<>();
887+
888+
HaxeSwitchStatement switchStatement = PsiTreeUtil.getParentOfType(extractedValue, HaxeSwitchStatement.class);
889+
buildExtractVarPath(extractedValue, true, objectPath, switchStatement);
890+
891+
Collections.reverse(objectPath);
892+
// workaround for switch on literal array (ex. switch (["mixed Types", 1, false]{...}))
893+
// as we are not going to look for generics in these situations to determine type.
894+
boolean isLiteralInSwitchExpression = isLiteralInSwitchExpression(resolve, extractedValueRef);
895+
int offset = isLiteralInSwitchExpression ? 1 : 0;
896+
897+
ResultHolder typePointer = result;
898+
for (int i = offset; i < objectPath.size(); i++) {
899+
Object o = objectPath.get(i);
900+
if (typePointer == null || typePointer.isUnknown()) break;
901+
902+
if (o instanceof Integer index) {
903+
typePointer = typeFromArray(typePointer, index);
904+
//TODO do we need support for objects here ?
905+
// } else if (o instanceof String name) {
906+
// typePointer = typeFromObjectName(typePointer,name);
907+
}
908+
}
909+
return typePointer != null ? typePointer : createUnknown(extractedValueRef);
910+
}
911+
}
912+
return result;
877913
}
878-
return createUnknown(extractedValue);
914+
return createUnknown(extractedValueRef);
879915
}
880916

917+
private static boolean isLiteralInSwitchExpression(PsiElement resolve, @NotNull HaxeEnumExtractedValueReference extractedValueRef) {
918+
HaxeLiteralExpression isLiteral = PsiTreeUtil.getParentOfType(resolve, HaxeLiteralExpression.class, false, HaxeSwitchStatement.class);
919+
HaxeArrayLiteral isInsideArrayLiteral = PsiTreeUtil.getParentOfType(resolve, HaxeArrayLiteral.class, false, HaxeSwitchStatement.class);
920+
HaxeSwitchStatement resolvedSwitchParent = PsiTreeUtil.getParentOfType(resolve, HaxeSwitchStatement.class);
921+
if(resolvedSwitchParent == null) return false;
922+
boolean isInSameSwitch = PsiTreeUtil.isAncestor(resolvedSwitchParent.getSwitchBlock(), extractedValueRef, false);
923+
return isInSameSwitch && (isLiteral != null || isInsideArrayLiteral != null);
924+
}
925+
926+
private static ResultHolder typeFromArray(ResultHolder typePointer, Integer index) {
927+
928+
SpecificHaxeClassReference classType = typePointer.getClassType();
929+
if(classType != null){
930+
if(classType.fullyResolveTypeDefAndUnwrapNullTypeReference() instanceof SpecificHaxeClassReference classReference) {
931+
if(classReference.isArray()) {
932+
@NotNull ResultHolder[] specifics = classReference.getSpecifics();
933+
if(specifics.length == 1) return specifics[0];
934+
// }else {
935+
// TODO considder checking array access in other types for expected return value
936+
// - verify if its supported first
937+
}
938+
}
939+
}
940+
return null;
941+
}
881942

882943

883944
static ResultHolder handleForStatement(

src/test/java/com/intellij/plugins/haxe/ide/HaxeSemanticAnnotatorTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,11 @@ public void testSwitchPatternMatching() throws Throwable {
10411041
myFixture.enableInspections(HaxeUnresolvedSymbolInspection.class);
10421042
doTestNoFixWithWarnings();
10431043
}
1044+
@Test
1045+
public void testSwitchPatternMatchingArrays() throws Throwable {
1046+
myFixture.enableInspections(HaxeUnresolvedSymbolInspection.class);
1047+
doTestNoFixWithWarnings();
1048+
}
10441049

10451050
@Test
10461051
public void testSwitchStatements() throws Throwable {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class PatternMachingTest {
2+
3+
public function test1DArray() {
4+
var myArray = [1, 2, 3];
5+
var s = switch (myArray) {
6+
case [a, b, c]: a + b + c;
7+
case a: 0;
8+
}
9+
trace(s);
10+
}
11+
12+
public function test2DArray() {
13+
var myArray = [[1, 2, 3], [4, 5, 6]];
14+
var s = switch (myArray) {
15+
case [[a, b, _],[_,c,_]]: a + b + c;
16+
case a: 0;
17+
}
18+
trace(s);
19+
}
20+
public function testArrayInObject() {
21+
var myObjectWithArray = {arr:[[1,2], [3]]};
22+
var s = switch (myObjectWithArray) {
23+
case {arr:[[a, b], [c]] }: a + b + c;
24+
case a: 0;
25+
}
26+
}
27+
28+
}

0 commit comments

Comments
 (0)