Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiresolve to alias and defmodule #405

Merged
merged 4 commits into from
Sep 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions gen/org/elixir_lang/psi/ElixirUnmatchedQualifiedAlias.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/org/elixir_lang/Elixir.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -2531,6 +2531,7 @@ unmatchedQualifiedAlias ::= unmatchedExpression dotInfixOperator alias
implements = "org.elixir_lang.psi.QualifiedAlias"
methods = [
fullyQualifiedName
getName
getNameIdentifier
getReference
isModuleName
Expand Down
4 changes: 2 additions & 2 deletions src/org/elixir_lang/psi/impl/ElixirPsiImplUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -2590,8 +2590,8 @@ public static String getName(@NotNull ElixirAlias alias) {
}

@NotNull
public static String getName(@NotNull ElixirMatchedQualifiedAlias matchedQualifiedAlias) {
return matchedQualifiedAlias.getText();
public static String getName(@NotNull QualifiedAlias qualifiedAlias) {
return qualifiedAlias.getText();
}

@Contract(pure = true)
Expand Down
65 changes: 56 additions & 9 deletions src/org/elixir_lang/psi/scope/module/MultiResolve.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package org.elixir_lang.psi.scope.module;

import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubIndex;
import com.intellij.psi.util.PsiTreeUtil;
import org.elixir_lang.psi.NamedElement;
import org.elixir_lang.psi.scope.Module;
import org.elixir_lang.psi.stub.index.AllName;
import org.elixir_lang.reference.module.UnaliasedName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static org.elixir_lang.Module.concat;
import static org.elixir_lang.Module.split;
import static org.elixir_lang.psi.impl.ElixirPsiImplUtil.ENTRANCE;

Expand All @@ -27,6 +36,19 @@ public static List<ResolveResult> resolveResultList(@NotNull String name,
* Private Static Methods
*/

@NotNull
private static Collection<NamedElement> indexedNamedElements(@NotNull PsiNamedElement match,
@NotNull String unaliasedName) {
Project project = match.getProject();
return StubIndex.getElements(
AllName.KEY,
unaliasedName,
project,
GlobalSearchScope.allScope(project),
NamedElement.class
);
}

@Nullable
private static List<ResolveResult> resolveResultList(@NotNull String name,
boolean incompleteCode,
Expand All @@ -42,6 +64,20 @@ private static List<ResolveResult> resolveResultList(@NotNull String name,
return multiResolve.getResolveResultList();
}

@NotNull
private static String unaliasedName(@NotNull PsiNamedElement match, @NotNull List<String> namePartList) {
String matchUnaliasedName = UnaliasedName.unaliasedName(match);

List<String> unaliasedNamePartList = new ArrayList<String>(namePartList.size());
unaliasedNamePartList.add(matchUnaliasedName);

for (int i = 1; i < namePartList.size(); i++) {
unaliasedNamePartList.add(namePartList.get(i));
}

return concat(unaliasedNamePartList);
}

/*
* Fields
*/
Expand Down Expand Up @@ -84,26 +120,28 @@ public List<ResolveResult> getResolveResultList() {
protected boolean executeOnAliasedName(@NotNull PsiNamedElement match,
@NotNull String aliasedName,
@NotNull ResolveState state) {
Boolean validResult = null;

if (aliasedName.equals(name)) {
validResult = true;
List<String> namePartList = split(name);

// adds `Foo.SSH` in `alias Foo.SSH`
addToResolveResultList(match, true);

// adds `defmodule Foo.SSH` for `alias Foo.SSH`
addUnaliasedNamedElementsToResolveResultList(match, namePartList);
} else {
List<String> namePartList = split(name);
String firstNamePart = namePartList.get(0);

// alias Foo.SSH, then SSH.Key is name
if (aliasedName.equals(firstNamePart)) {
validResult = true;
addToResolveResultList(match, true);

addUnaliasedNamedElementsToResolveResultList(match, namePartList);
} else if (incompleteCode && aliasedName.startsWith(name)) {
validResult = false;
addToResolveResultList(match, false);
}
}

if (validResult != null) {
addToResolveResultList(match, validResult);
}

return org.elixir_lang.psi.scope.MultiResolve.keepProcessing(incompleteCode, resolveResultList);
}

Expand All @@ -116,4 +154,13 @@ private void addToResolveResultList(@NotNull PsiElement element, boolean validRe
resolveResultList, new PsiElementResolveResult(element, validResult)
);
}

private void addUnaliasedNamedElementsToResolveResultList(@NotNull PsiNamedElement match, List<String> namePartList) {
String unaliasedName = unaliasedName(match, namePartList);
Collection<NamedElement> namedElementCollection = indexedNamedElements(match, unaliasedName);

for (PsiElement element : namedElementCollection) {
addToResolveResultList(element, true);
}
}
}
13 changes: 2 additions & 11 deletions src/org/elixir_lang/psi/scope/module/Variants.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
import com.intellij.psi.ResolveState;
import com.intellij.psi.stubs.StubIndex;
import com.intellij.util.containers.ContainerUtil;
import org.elixir_lang.psi.QualifiableAlias;
import org.elixir_lang.psi.scope.Module;
import org.elixir_lang.psi.stub.index.AllName;
import org.elixir_lang.reference.module.ResolvableName;
import org.elixir_lang.reference.module.UnaliasedName;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
Expand Down Expand Up @@ -80,15 +79,7 @@ protected boolean executeOnAliasedName(@NotNull PsiNamedElement match, @NotNull
)
);

final String unaliasedName;

if (match instanceof QualifiableAlias) {
QualifiableAlias matchQualfiableAlias = (QualifiableAlias) match;

unaliasedName = ResolvableName.resolvableName(matchQualfiableAlias);
} else {
unaliasedName = match.getName();
}
String unaliasedName = UnaliasedName.unaliasedName(match);

if (unaliasedName != null) {
List<String> unaliasedNestedNames = ContainerUtil.findAll(
Expand Down
102 changes: 102 additions & 0 deletions src/org/elixir_lang/reference/module/UnaliasedName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package org.elixir_lang.reference.module;

import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import org.elixir_lang.psi.*;
import org.elixir_lang.psi.call.Call;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static org.elixir_lang.psi.call.name.Function.ALIAS;
import static org.elixir_lang.psi.call.name.Module.KERNEL;
import static org.elixir_lang.psi.impl.ElixirPsiImplUtil.finalArguments;
import static org.elixir_lang.psi.impl.ElixirPsiImplUtil.hasKeywordKey;

public class UnaliasedName {
/*
* Public Static Methods
*/

@Nullable
public static String unaliasedName(@NotNull PsiNamedElement namedElement) {
String unaliasedName;

if (namedElement instanceof QualifiableAlias) {
unaliasedName = unaliasedName((QualifiableAlias) namedElement);
} else {
unaliasedName = namedElement.getName();
}

return unaliasedName;
}

/*
* Private Static Methods
*/

@Nullable
private static String down(@NotNull PsiElement element) {
String unaliasedName = null;

if (element instanceof QualifiableAlias) {
PsiNamedElement namedElement = (PsiNamedElement) element;

unaliasedName = namedElement.getName();
}

return unaliasedName;
}

@Nullable
private static String unaliasedName(@NotNull QualifiableAlias qualifiableAlias) {
return up(qualifiableAlias.getParent(), qualifiableAlias);
}

@Nullable
private static String up(@NotNull Call call, @NotNull QualifiableAlias entrance) {
String unaliasedName = null;

if (call.isCalling(KERNEL, ALIAS)) {
PsiElement[] finalArguments = finalArguments(call);

if (finalArguments != null && finalArguments.length > 0) {
PsiElement firstArgument = finalArguments[0];

unaliasedName = down(firstArgument);
}
}

return unaliasedName;
}

@Nullable
private static String up(@Nullable PsiElement element, @NotNull QualifiableAlias entrance) {
String unaliasedName = null;

if (element instanceof Call) {
unaliasedName = up((Call) element, entrance);
} else if (element instanceof ElixirAccessExpression ||
element instanceof QuotableArguments ||
element instanceof QuotableKeywordList) {
unaliasedName = up(element.getParent(), entrance);
} else if (element instanceof ElixirMultipleAliases) {
unaliasedName = down(entrance);
} else if (element instanceof QuotableKeywordPair) {
unaliasedName =up((QuotableKeywordPair) element, entrance);
}

return unaliasedName;
}

@Nullable
private static String up(@NotNull QuotableKeywordPair element, @NotNull QualifiableAlias entrance) {
String unaliasedName = null;

if (hasKeywordKey(element, "as")) {
unaliasedName = up(element.getParent(), entrance);
}

return unaliasedName;
}

}