package org.angularjs.codeInsight;
import com.intellij.lang.javascript.DialectDetector;
import com.intellij.lang.javascript.JSTokenTypes;
import com.intellij.lang.javascript.ecmascript6.TypeScriptResolveProcessor;
import com.intellij.lang.javascript.psi.JSDefinitionExpression;
import com.intellij.lang.javascript.psi.JSPsiElementBase;
import com.intellij.lang.javascript.psi.ecmal4.JSClass;
import com.intellij.lang.javascript.psi.impl.JSReferenceExpressionImpl;
import com.intellij.lang.javascript.psi.resolve.JSReferenceExpressionResolver;
import com.intellij.lang.javascript.psi.resolve.JSResolveResult;
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.angularjs.index.AngularControllerIndex;
import org.angularjs.index.AngularFilterIndex;
import org.angularjs.index.AngularIndexUtil;
import org.angularjs.index.AngularJS2IndexingHandler;
import org.angularjs.lang.psi.AngularJSAsExpression;
import org.angularjs.lang.psi.AngularJSFilterExpression;
import org.angularjs.lang.psi.AngularJSRepeatExpression;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author Dennis.Ushakov
*/
public class AngularJSReferenceExpressionResolver extends JSReferenceExpressionResolver {
public AngularJSReferenceExpressionResolver(JSReferenceExpressionImpl expression, boolean ignorePerformanceLimits) {
super(expression, ignorePerformanceLimits);
}
public static Collection<JSPsiElementBase> getItemsByName(final String name, PsiElement element) {
final Collection<JSPsiElementBase> result = new ArrayList<>();
AngularJSProcessor.process(element, element1 -> {
if (name.equals(element1.getName())) {
result.add(element1);
}
});
return result;
}
@NotNull
@Override
public ResolveResult[] resolve(@NotNull JSReferenceExpressionImpl expression, boolean incompleteCode) {
if (myReferencedName == null) return ResolveResult.EMPTY_ARRAY;
if (myRef.getParent() instanceof JSDefinitionExpression) {
final PsiElement sibling = PsiTreeUtil.prevVisibleLeaf(myRef);
if (sibling != null && sibling.getNode().getElementType() == JSTokenTypes.LET_KEYWORD) {
return new JSResolveResult[]{new JSResolveResult(myRef)};
}
final AngularJSRepeatExpression repeat = PsiTreeUtil.getParentOfType(myRef, AngularJSRepeatExpression.class);
if (repeat != null) {
for (JSDefinitionExpression def : repeat.getDefinitions()) {
if (PsiTreeUtil.isAncestor(def, myRef, true)) return new JSResolveResult[]{new JSResolveResult(myRef)};
}
}
final AngularJSAsExpression as = PsiTreeUtil.getParentOfType(myRef, AngularJSAsExpression.class);
if (as != null) {
if (PsiTreeUtil.isAncestor(as.getDefinition(), myRef, true)) return new JSResolveResult[]{new JSResolveResult(myRef)};
}
JSClass clazz = myRef.getQualifier() == null ? AngularJS2IndexingHandler.findDirectiveClass(myRef) : null;
if (clazz != null && DialectDetector.isTypeScript(clazz)) {
final TypeScriptResolveProcessor localProcessor = new TypeScriptResolveProcessor(myReferencedName, myContainingFile, myRef, incompleteCode);
localProcessor.setToProcessHierarchy(true);
JSReferenceExpressionImpl.doProcessLocalDeclarations(clazz, myQualifier, localProcessor, false, false, null);
return localProcessor.getResultsAsResolveResults();
}
}
if (AngularJSAsExpression.isAsControllerRef(myRef, myRef.getParent())) {
final PsiElement resolve = AngularIndexUtil.resolve(myParent.getProject(), AngularControllerIndex.KEY, myReferencedName);
if (resolve != null) {
return new JSResolveResult[]{new JSResolveResult(resolve)};
}
} else if (AngularJSFilterExpression.isFilterNameRef(myRef, myParent)) {
final PsiElement resolve = AngularIndexUtil.resolve(myParent.getProject(), AngularFilterIndex.KEY, myReferencedName);
if (resolve != null) {
return new JSResolveResult[] {new JSResolveResult(resolve)};
}
} else if (myQualifier == null) {
final Collection<JSPsiElementBase> localVariables = getItemsByName(myReferencedName, myRef);
if (!localVariables.isEmpty()) {
return ContainerUtil.map2Array(localVariables, JSResolveResult.class, item -> new JSResolveResult(item));
}
}
return super.resolve(expression, incompleteCode);
}
}