package org.elixir_lang.reference.module; import com.intellij.psi.PsiElement; import org.elixir_lang.psi.ElixirAccessExpression; import org.elixir_lang.psi.ElixirMultipleAliases; import org.elixir_lang.psi.QualifiableAlias; import org.elixir_lang.psi.QualifiedMultipleAliases; import org.elixir_lang.psi.call.Call; import org.elixir_lang.psi.call.StubBased; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import static org.elixir_lang.Module.concat; import static org.elixir_lang.psi.call.name.Function.__MODULE__; import static org.elixir_lang.psi.call.name.Module.KERNEL; import static org.elixir_lang.structure_view.element.CallDefinitionClause.enclosingModularMacroCall; public class ResolvableName { /* * Public Static Methods */ /** * The full name of the qualifiable alias, with any multiple aliases expanded */ @Nullable public static String resolvableName(@NotNull QualifiableAlias qualifiableAlias) { String resolvableName = qualifiableAlias.fullyQualifiedName(); List<String> tail = null; if (resolvableName != null) { tail = new ArrayList<String>(); tail.add(resolvableName); } return up(qualifiableAlias.getParent(), tail); } /* * Private Static Methods */ @Nullable private static List<String> down(@NotNull Call qualifier) { List<String> nameList = null; if (qualifier.isCalling(KERNEL, __MODULE__, 0)) { Call enclosingCall = enclosingModularMacroCall(qualifier); if (enclosingCall != null && enclosingCall instanceof StubBased) { StubBased enclosingStubBasedCall = (StubBased) enclosingCall; String canonicalName = enclosingStubBasedCall.canonicalName(); if (canonicalName != null) { nameList = new ArrayList<String>(); nameList.add(canonicalName); } } } return nameList; } @Nullable private static List<String> down(@NotNull QualifiableAlias qualifier) { String resolvableName = qualifier.getName(); List<String> nameList = null; if (resolvableName != null) { nameList = new ArrayList<String>(); nameList.add(resolvableName); } return nameList; } @Nullable private static List<String> down(@NotNull PsiElement qualifier) { List<String> nameList = null; if (qualifier instanceof Call) { nameList = down((Call) qualifier); } else if (qualifier instanceof ElixirAccessExpression) { nameList = down(qualifier.getChildren()); } else if (qualifier instanceof QualifiableAlias) { nameList = down((QualifiableAlias) qualifier); } return nameList; } @Nullable private static List<String> down(@NotNull PsiElement[] qualifiers) { List<String> nameList = null; for (PsiElement qualifier : qualifiers) { List<String> qualifierNameList = down(qualifier); if (qualifierNameList != null) { if (nameList == null) { nameList = new ArrayList<String>(qualifierNameList.size()); } nameList.addAll(qualifierNameList); } } return nameList; } @Nullable private static String up(@Nullable PsiElement ancestor, @Nullable List<String> tail) { String resolvableName = null; if (ancestor instanceof ElixirAccessExpression || ancestor instanceof ElixirMultipleAliases) { resolvableName = up(ancestor.getParent(), tail); } else if (ancestor instanceof QualifiedMultipleAliases) { resolvableName = up((QualifiedMultipleAliases) ancestor, tail); } else if (tail != null) { resolvableName = concat(tail); } return resolvableName; } @Nullable private static String up(@NotNull QualifiedMultipleAliases ancestor, @Nullable List<String> tail) { PsiElement[] children = ancestor.getChildren(); int operatorIndex = org.elixir_lang.psi.operation.Normalized.operatorIndex(children); PsiElement qualifier = org.elixir_lang.psi.operation.infix.Normalized.leftOperand(children, operatorIndex); List<String> qualifierNameList = null; if (qualifier != null) { qualifierNameList = down(qualifier); } List<String> nameList; if (qualifierNameList != null) { nameList = qualifierNameList; if (tail != null) { qualifierNameList.addAll(tail); } } else { nameList = tail; } String resolvableName = null; if (nameList != null) { resolvableName = concat(nameList); } return resolvableName; } }