Skip to content

Commit

Permalink
misc resolver refactoring and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
m0rkeulv committed Feb 19, 2024
1 parent 208a4d8 commit 059e413
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 40 deletions.
27 changes: 15 additions & 12 deletions src/main/java/com/intellij/plugins/haxe/lang/psi/HaxeResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
@CustomLog
public class HaxeResolver implements ResolveCache.AbstractResolver<HaxeReference, List<? extends PsiElement>> {
public static final int MAX_DEBUG_MESSAGE_LENGTH = 200;
public static final Key<Boolean> isExtensionKey = new Key<>("isExtensionKey");
public static final Key<String> typeHintKey = new Key<>("typeHint");
private static final Key<Boolean> skipCacheKey = new Key<>("skipCache");

Expand Down Expand Up @@ -158,7 +157,7 @@ private List<? extends PsiElement> doResolve(@NotNull HaxeReference reference, b
log.trace(traceMsg("Resolving reference: " + referenceText));
}

List<? extends PsiElement> foundElements = doResolveInner(reference, incompleteCode, referenceText);
List<? extends PsiElement> foundElements = doResolveInner(reference, incompleteCode, referenceText);

if (traceEnabled) {
log.trace(traceMsg("Finished reference: " + referenceText));
Expand Down Expand Up @@ -274,11 +273,10 @@ private List<? extends PsiElement> doResolveInner(@NotNull HaxeReference referen
if (result == null) {
LogResolution(reference, "failed after exhausting all options.");
}

if (result == null) {
// to avoid caching empty due to already being resolved we mark
// elements so we know if we want to cache as not found or just skip (null is not cached, empty list is cached)
if (reference.getUserData(skipCacheKey) == Boolean.TRUE) {
if (incompleteCode || reference.getUserData(skipCacheKey) == Boolean.TRUE) {
if (log.isTraceEnabled()) {
String message = "result is empty and skip cache flag is true, skipping cache for: " + referenceText;
traceAs(log, HaxeDebugUtil.getCallerStackFrame(), message);
Expand Down Expand Up @@ -867,12 +865,19 @@ private List<? extends PsiElement> checkIsAlias(HaxeReference reference) {
}

private List<? extends PsiElement> checkIsFullyQualifiedStatement(@NotNull HaxeReference reference) {
if (PsiTreeUtil.getParentOfType(reference,
HaxePackageStatement.class,
HaxeImportStatement.class,
HaxeUsingStatement.class) != null && reference instanceof HaxeReferenceExpression) {
LogResolution(reference, "via parent/package import.");
return asList(resolveQualifiedReference((HaxeReferenceExpression)reference));
if (reference instanceof HaxeReferenceExpression) {
HaxeStatementPsiMixin parent = PsiTreeUtil.getParentOfType(reference,
HaxePackageStatement.class,
HaxeImportStatement.class,
HaxeUsingStatement.class);
if (parent != null) {

//TODO check for @:using on haxeType and add to using (this might not be the correct place, but its a reminder to add it somewhere in the resolver logic)
// TODO if using, include all members from file for resolving ( qualified path / package + memberName in using should resolve)

LogResolution(reference, "via parent/package import.");
return asList(resolveQualifiedReference(reference));
}
}
return null;
}
Expand Down Expand Up @@ -935,7 +940,6 @@ private List<? extends PsiElement> resolveChain(HaxeReference lefthandExpression
.findExtensionMethod(identifier, leftExpression.getSpecificClassReference(reference, leftExpression.getGenericResolver()));
if (null != foundMethod && !foundMethod.HasNoUsingMeta()) {

reference.putUserData(isExtensionKey, true);
if (log.isTraceEnabled()) log.trace("Found method in 'using' import: " + foundMethod.getName());
return asList(foundMethod.getBasePsi());
}
Expand Down Expand Up @@ -1214,7 +1218,6 @@ private static List<? extends PsiElement> resolveByClassAndSymbol(@Nullable Haxe
HaxeUsingModel model = usingModels.get(i);
HaxeMethodModel method = model.findExtensionMethod(reference.getReferenceName(), leftClassReference);
if (method != null) {
reference.putUserData(isExtensionKey, true);
return asList(method.getNamePsi());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,23 +178,26 @@ public PsiElement resolve() {
}

public boolean resolveIsStaticExtension() {
// @TODO: DIRTY HACK! to avoid rewriting all the code!
Boolean result;
if (this instanceof HaxeCallExpression) {
PsiReference child = this.getFirstChild().getReference();
if (!(child instanceof HaxeReferenceExpression)) return false;
HaxeReferenceExpression reference = (HaxeReferenceExpression)child;
result = reference.getUserData(HaxeResolver.isExtensionKey);
if (result == null) {
HaxeResolver.INSTANCE.resolve(reference, true);
result = reference.getUserData(HaxeResolver.isExtensionKey);
PsiReference referenceChain = this.getFirstChild().getReference();
if (referenceChain instanceof HaxeReferenceExpression referenceExpression) {
PsiElement method = referenceExpression.resolve();
if (method instanceof HaxeMethod haxeMethod) {
if (!haxeMethod.isStatic()) return false; // only static methods can be extensions (compiler: Cannot access static field XXX from a class instance)

PsiElement ChainBeforeMethod = referenceExpression.getChildren()[0];
if (ChainBeforeMethod instanceof HaxeIdentifier) return false; // not chain, got method identifer
if (ChainBeforeMethod instanceof HaxeReferenceExpression referenceExpression1) {
PsiElement caller = referenceExpression1.resolve();
// todo find using import statement for methods declaring class and confirm "using"
return !(caller instanceof HaxeClass || caller instanceof HaxeImportAlias);
}else {
return true;
}
}
}
}
else {
HaxeResolver.INSTANCE.resolve(this, true);
result = this.getUserData(HaxeResolver.isExtensionKey);
}
return result == null ? false : result;
return false;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.intellij.plugins.haxe.util.*;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.search.SearchScope;
Expand Down Expand Up @@ -80,7 +81,7 @@ static public HaxeExpressionEvaluatorContext evaluate(PsiElement element, HaxeEx
private static ResultHolder handleWithRecursionGuard(PsiElement element,
HaxeExpressionEvaluatorContext context,
HaxeGenericResolver resolver) {
if (element == null) return null;
if (element == null ) return null;
HashSet<PsiElement> elements = resolvesInProcess.get();
try {
if (elements.contains(element)) return null;
Expand Down Expand Up @@ -861,7 +862,9 @@ else if (subelement instanceof HaxeSwitchCaseExpr caseExpr) {

else {
// attempt to resolve subelement using default handle logic
typeHolder = handleWithRecursionGuard(subelement, context, resolver);
if (!(subelement instanceof PsiPackage)) {
typeHolder = handleWithRecursionGuard(subelement, context, resolver);
}
if (typeHolder == null) {
typeHolder = SpecificTypeReference.getUnknown(element).createHolder();
}
Expand Down Expand Up @@ -1592,27 +1595,59 @@ public static ResultHolder searchReferencesForTypeParameters(final HaxePsiField

@NotNull String[] specificNames = classResolver.names();
HaxeMethodModel methodModel = methodDeclaration.getModel();
HaxeGenericResolver methodResolver = methodModel.getGenericResolver(null);
@NotNull String[] methodSpecificNames = methodResolver.names();

List<String> specificsForClass = Arrays.asList(specificNames);
specificsForClass.removeAll(Arrays.asList(methodSpecificNames));
// make sure we are using class level typeParameters (and not method level)
if (methodModel.getGenericParams().isEmpty()) {
HaxeCallExpressionList list = callExpression.getExpressionList();
if (list != null) {
List<HaxeExpression> arguments = list.getExpressionList();
List<HaxeParameterModel> parameters = methodDeclaration.getModel().getParameters();
for (HaxeParameterModel parameter : parameters) {
if (parameter.getType().isTypeParameter()) {
for (int i = 0; i < Math.min(specificNames.length, arguments.size()); i++) {
if (specificNames[i].equals(parameter.getTypeTagPsi().getTypeOrAnonymous().getText())) {
// we could try to map parameters and args, but in most cases this probably won't be necessary and it would make this part very complex
@NotNull ResultHolder[] specifics = type.getSpecifics();
if (specifics[i].isUnknown()) {
//TODO This really need to be cleaned up and is one big messy hack at the moment

// correct way to solve it.
//- find method parameters that are typeParameters from class (not from method)
// - try to match parameters and arguments and create map with typeParameters to resolved argument type
// update type specifics with map



HaxeClassModel classModel = classType.getHaxeClassModel();
if (classModel == null) continue;
List<HaxeGenericParamModel> params = classModel.getGenericParams();
@NotNull ResultHolder[] specifics = type.getSpecifics();
Map<String, Integer>specificsMap = new HashMap<>();
for (int i = 0; i < specifics.length; i++) {
HaxeGenericParamModel model = params.get(i);
ResultHolder specific = specifics[i];
if (specific.getType() instanceof SpecificHaxeClassReference classReference) {
if (classReference.isUnknown() || classReference.isTypeParameter()) {
specificsMap.put(model.getName(), i);
}
}
}

Set<String> genericNames = specificsMap.keySet();

int inputCount = Math.min(parameters.size(), arguments.size());
for (int i = 0; i<inputCount; i++) {
SpecificTypeReference paramType = parameters.get(i).getType().getType();
if (paramType instanceof SpecificHaxeClassReference classReference && classReference.isTypeParameter()) {
String name = classReference.getClassName();

if (genericNames.contains(name)) {
Integer index = specificsMap.get(name);
if (specifics[index].isUnknown()) {
ResultHolder handle = handle(arguments.get(i), context, resolver);
if (specifics[i].isUnknown()) {
specifics[i] = handle;
if (specifics[index].isUnknown()) {
specifics[index] = handle;
}else {
ResultHolder unified = HaxeTypeUnifier.unify(handle, specifics[i]);
specifics[i] = unified;
ResultHolder unified = HaxeTypeUnifier.unify(handle, specifics[index]);
specifics[index] = unified;
}
}
}
}
}
Expand Down

0 comments on commit 059e413

Please sign in to comment.