package org.elixir_lang.psi.call; import com.intellij.psi.NavigatablePsiElement; import com.intellij.psi.PsiElement; import org.apache.commons.lang.math.IntRange; import org.elixir_lang.psi.ElixirDoBlock; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * A general function or macro call. */ public interface Call extends NavigatablePsiElement { /** * * @return name of the function/macro as given in the source */ @Nullable String functionName(); /** * * @return */ @Nullable PsiElement functionNameElement(); /** * @return `null` if no `do` block. */ @Nullable ElixirDoBlock getDoBlock(); /** * Whether this call has a {@code do} block or a {@code :do} keyword, so it is a macro * * @return {@code true} if {@link #getDoBlock()} is NOT {@code null} or there is a {@code "do"} keyword argument * @see org.elixir_lang.psi.impl.ElixirPsiImplUtil#keywordArgument(Call, String) */ boolean hasDoBlockOrKeyword(); /** * Whether this call is calling the given `functionName` in the `resolvedModuleName` with any arity * * @param resolvedModuleName the expected {@link #resolvedModuleName()} * @param functionName the expected {@link #functionName()} * @return {@code true} if this call has non-{@code null} {@link #resolvedModuleName()} that equals * {@code resolvedModuleName} and has non-{@code null} {@link #functionName()} that equals * {@code functionName}; otherwise, {@code false}. */ boolean isCalling(@NotNull final String resolvedModuleName, @NotNull final String functionName); /** * Whether this call is calling the given `functionName` in the `resolvedModuleName` with the * `resolvedArity` * * @param resolvedModuleName the expected {@link #resolvedModuleName()} * @param functionName the expected {@link #functionName()} * @param resolvedFinalArity the expected {@link #resolvedFinalArity()} * @return {@code true} if this call has non-{@code null} {@link #resolvedModuleName()} that equals * {@code resolvedModuleName} and has non-{@code null} {@link #functionName()} that equals * {@code functionName} and the {@link #resolvedFinalArity}; otherwise, {@code false}. */ boolean isCalling(@NotNull final String resolvedModuleName, @NotNull final String functionName, final int resolvedFinalArity); /** * Whether {@code call} is of the named macro. * * Differs from {@link #isCallingMacro(String, String, int)} because no arity is necessary, * which is useful for special forms, which don't have a set arity. (That's actually why they need to be special * forms since Erlang/Elixir doesn't support variable arity functions otherwise.) * * @param resolvedModuleName the expected {@link Call#resolvedModuleName()} * @param functionName the expected {@link Call#functionName()} * @return {@code true} if all arguments match and {@link Call#getDoBlock()} is not {@code null}; {@code false}. */ boolean isCallingMacro(@NotNull final String resolvedModuleName, @NotNull final String functionName); /** * Whether {@code call} is of the named macro. * * Differs from {@link #isCalling(String, String, int)} because this function ensures there is a {@code do} * block. If the macro can be called without a {@code do} block, then * {@link #isCalling(String, String, int)} should be used instead. * * @param resolvedModuleName the expected {@link #resolvedModuleName()} * @param functionName the expected {@link #functionName()} * @param resolvedFinalArity the expected {@link #resolvedFinalArity()} * @return {@code true} if all arguments match and {@link #getDoBlock()} is not {@code null}; {@code false}. */ boolean isCallingMacro(@NotNull final String resolvedModuleName, @NotNull final String functionName, final int resolvedFinalArity); /** * * @return name of the qualifying module as given in the source */ @Nullable String moduleName(); /** * The arguments directly after the {@link #functionName}. If the function cannot have arguments, then this will `null` * * <p> * NOTE: Individual elements of the returned {@code PsiElement[]} may be {@code null} to indicate the argument * is expected to be there, such as for {@link org.elixir_lang.psi.operation.Infix}, but it is missing or has an * error due to Pratt Parser error recovery. * </p> * * @return {@code null} if function cannot take arguments, such as an ambiguous variable or no parentheses, * no arguments, function call like {@code foo}; * @return {@code PsiElement[]} if the function takes arguments. * Importantly, {@code foo} can be distinguished from {@code foo()} because the former returns {@code null} while * the latter returns {@code new PsiElement[0]} */ @Nullable PsiElement[] primaryArguments(); /** * The number of {#link primaryArguments}. * * @return the number of primary arguments without counting the {@code do block} or any pipelines; {@code null} * if {@link #primaryArguments()} is {@code null}. */ @Nullable Integer primaryArity(); /** * The arguments in the second set of parentheses. * * @return {@code null} if the call cannot or does not have a second set of parentheses; otherwise, * {@code PsiElement[]} */ @Nullable PsiElement[] secondaryArguments(); /** * The number of {#link secondaryArguments}. * * @return the number of secondary arguments without counting the {@code do block} or any pipelines; {@code null} if * {@link #secondaryArguments()} is {@code null}; */ @Nullable Integer secondaryArity(); /** * @return name of the qualifying module after taking into account any aliases */ @Nullable String resolvedModuleName(); /** * The total number of primary arguments for the final expanded function call. * * @return the number of primary arguments plus one for a {@code do} block if present plus one if the right operand * of a pipe; If {@code foo} is the function call, and so it has {@code null} {@link #primaryArity()}, * {@code foo do} or {@code |> foo} would have a resolve primary arity of {@code null}. Otherwise, the resolved * primary arity matches {@link #primaryArity()} and it {@code null}. */ @Nullable Integer resolvedPrimaryArity(); /** * The final arity that is non-{@code null}. * * @return {@link #resolvedSecondaryArity()} if it is not {@code null}; {@link #resolvedPrimaryArity()} if it is not * {@code null}; otherwise, {@code 0}. */ int resolvedFinalArity(); /** * The final arities produced by turning default arguments on and off. * * @return the minimum arity with all defaults active to the maximum arity with all defaults overridden */ @NotNull IntRange resolvedFinalArityRange(); /** * The total number of primary arguments for the final expanded function call. * * @return the number of primary arguments plus one for a {@code do} block if present plus one if the right operand * of a pipe; {@code null} only if there is no second set of parentheses. */ @Nullable Integer resolvedSecondaryArity(); }