package org.elixir_lang.structure_view.element; import com.intellij.ide.util.treeView.smartTree.TreeElement; import com.intellij.navigation.ItemPresentation; import com.intellij.psi.ElementDescriptionLocation; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.usageView.UsageViewTypeLocation; import org.elixir_lang.navigation.item_presentation.Parent; import org.elixir_lang.psi.ElixirAccessExpression; import org.elixir_lang.psi.ElixirList; import org.elixir_lang.psi.call.Call; import org.elixir_lang.psi.impl.ElixirPsiImplUtil; import org.elixir_lang.structure_view.element.modular.Modular; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.elixir_lang.psi.call.name.Function.DEFDELEGATE; import static org.elixir_lang.psi.call.name.Module.KERNEL; import static org.elixir_lang.psi.impl.ElixirPsiImplUtil.stripAccessExpression; public class Delegation extends Element<Call> { /* * Fields */ @NotNull private final List<TreeElement> childList = new ArrayList<TreeElement>(); @NotNull private final Modular modular; /* * Static Methods */ public static List<Call> callDefinitionHeadCallList(Call defdelegateCall) { List<Call> callDefinitionHeadCallList = null; PsiElement[] finalArguments = ElixirPsiImplUtil.finalArguments(defdelegateCall); assert finalArguments != null; assert finalArguments.length > 0; PsiElement firstFinalArgument = finalArguments[0]; if (firstFinalArgument instanceof ElixirAccessExpression) { PsiElement accessExpressionChild = stripAccessExpression(firstFinalArgument); if (accessExpressionChild instanceof ElixirList) { ElixirList list = (ElixirList) accessExpressionChild; Call[] listCalls = PsiTreeUtil.getChildrenOfType(list, Call.class); callDefinitionHeadCallList = filterCallDefinitionHeadCallList(listCalls); } } else if (firstFinalArgument instanceof Call) { Call call = (Call) firstFinalArgument; callDefinitionHeadCallList = filterCallDefinitionHeadCallList(call); } if (callDefinitionHeadCallList == null) { callDefinitionHeadCallList = Collections.emptyList(); } return callDefinitionHeadCallList; } @NotNull public static List<Call> filterCallDefinitionHeadCallList(Call... calls) { List<Call> callList = Collections.emptyList(); if (calls != null) { callList = new ArrayList<Call>(calls.length); for (Call call : calls) { if (CallDefinitionHead.is(call)) { callList.add(call); } } } return callList; } public static String elementDescription(Call call, ElementDescriptionLocation location) { String elementDescription = null; if (location == UsageViewTypeLocation.INSTANCE) { elementDescription = "delegation"; } return elementDescription; } public static boolean is(Call call) { return call.isCalling(KERNEL, DEFDELEGATE, 2); } /* * Constructors */ public Delegation(@NotNull Modular modular, @NotNull Call call) { super(call); this.modular = modular; } /* * * Instance Methods * */ /* * Public Instance Methods */ /** * If {@code true}, when delegated, the first argument passed to the delegated function will be relocated to the end * of the arguments when dispatched to the target. * * @return defaults to {@code false} and when keyword argument is not parsable as boolean. */ public boolean appendFirst() { PsiElement keywordValue = ElixirPsiImplUtil.keywordArgument(navigationItem, "append_first"); boolean appendFirst = false; if (keywordValue != null) { String keywordValueText = keywordValue.getText(); if (keywordValueText.equals("true")) { appendFirst = true; } } return appendFirst; } /** * The value of the {@code :as} keyword argument * * @return text of the {@code :as} keyword value */ @Nullable public String as() { return keywordArgumentText("as"); } @NotNull public List<Call> callDefinitionHeadCallList() { return callDefinitionHeadCallList(navigationItem); } public void definition(CallDefinition callDefinition) { childList.add(callDefinition); } /** * The calls defined by this delegation * * @return the list of {@link CallDefinition} elements; */ @NotNull @Override public TreeElement[] getChildren() { return childList.toArray(new TreeElement[childList.size()]); } /** * Returns the presentation of the tree element. * * @return the element presentation. */ @NotNull @Override public ItemPresentation getPresentation() { Parent parent = (Parent) modular.getPresentation(); String location = parent.getLocatedPresentableText(); return new org.elixir_lang.navigation.item_presentation.Delegation( location, to(), as(), appendFirst() ); } /** * The value of the {@code :to} keyword argument * * @return text of the {@code :to} keyword value */ @Nullable public String to() { return keywordArgumentText("to"); } /* * Private Instance Methods */ /** * The text of the {@code keywordValueText} keyword argument. * * @param keywordValueText the text of the keyword value * @return the {@code PsiElement.getText()} of the keyword value if the keyword argument exists of the * {@link Element#navigationItem}; {@code null} if the keyword argument does not exist. */ @Nullable private String keywordArgumentText(@NotNull final String keywordValueText) { PsiElement keywordValue = ElixirPsiImplUtil.keywordArgument(navigationItem, keywordValueText); String text = null; if (keywordValue != null) { text = keywordValue.getText(); } return text; } }