PY-2980 Unresolved reference for ForeignKey defined as string

This commit is contained in:
Ilya.Kazakevich
2014-05-20 22:34:03 +04:00
parent 202643b771
commit 68565aedf8
6 changed files with 74 additions and 20 deletions
@@ -12,4 +12,9 @@ public interface FQNamesProvider {
*/
@NotNull
String[] getNames();
/**
* @return is name of class (true) or function (false)
*/
boolean isClass();
}
@@ -2,14 +2,13 @@ package com.jetbrains.python.nameResolver;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyQualifiedNameOwner;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
/**
* @author Ilya.Kazakevich
@@ -52,25 +51,28 @@ public final class NameResolverTools {
elementToCheck = (PyElement)resolvedElement;
}
}
String qualifiedName = null;
if (elementToCheck instanceof PyQualifiedNameOwner) {
final String qualifiedName = ((PyQualifiedNameOwner)elementToCheck).getQualifiedName();
return getNames(namesProviders).contains(qualifiedName);
qualifiedName = ((PyQualifiedNameOwner)elementToCheck).getQualifiedName();
}
String className = null;
if (elementToCheck instanceof PyFunction) {
final PyClass aClass = ((PyFunction)elementToCheck).getContainingClass();
if (aClass != null) {
className = aClass.getQualifiedName();
}
}
for (final FQNamesProvider provider : namesProviders) {
final List<String> names = Arrays.asList(provider.getNames());
if (qualifiedName != null && names.contains(qualifiedName)) {
return true;
}
if (className != null && provider.isClass() && names.contains(className)) {
return true;
}
}
return false;
}
/**
* Returns set of names all providers provide
*
* @param providers providers to check
* @return set of names
*/
@NotNull
private static Collection<String> getNames(@NotNull final FQNamesProvider... providers) {
final Set<String> result = new HashSet<String>();
for (final FQNamesProvider provider : providers) {
result.addAll(Arrays.asList(provider.getNames()));
}
return result;
}
}
@@ -16,6 +16,7 @@
package com.jetbrains.python.psi;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.nameResolver.FQNamesProvider;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import org.jetbrains.annotations.NotNull;
@@ -66,6 +67,16 @@ public interface PyCallExpression extends PyExpression {
@Nullable
<T extends PsiElement> T getArgument(int index, String keyword, Class<T> argClass);
/**
* Returns the argument if one is present in the list.
*
* @param parameter parameter
* @param argClass argument expected type
* @return the argument or null
*/
@Nullable
<T extends PsiElement> T getArgument(@NotNull final FunctionParameter parameter, @NotNull Class<T> argClass);
@Nullable
PyExpression getKeywordArgument(String keyword);
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.nameResolver.FQNamesProvider;
import com.jetbrains.python.nameResolver.NameResolverTools;
@@ -361,6 +362,27 @@ public class PyCallExpressionHelper {
return false;
}
/**
* Returns argument if it exists and has appropriate type
* @param parameter argument
* @param argClass expected class
* @param expression call expression
* @param <T> expected class
* @return argument expression or null if has wrong type of does not exist
*/
@Nullable
public static <T extends PsiElement> T getArgument(
@NotNull final FunctionParameter parameter,
@NotNull final Class<T> argClass,
@NotNull final PyCallExpression expression) {
final PyArgumentList list = expression.getArgumentList();
if (list == null) {
return null;
}
return PyUtil.as(list.getValueExpressionForParam(parameter), argClass);
}
@Nullable
public static PyExpression getKeywordArgument(PyCallExpression expr, String keyword) {
for (PyExpression arg : expr.getArguments()) {
@@ -18,6 +18,7 @@ package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.nameResolver.FQNamesProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -72,6 +73,12 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress
return getArgument(index, argClass);
}
@Nullable
@Override
public <T extends PsiElement> T getArgument(@NotNull final FunctionParameter parameter, @NotNull final Class<T> argClass) {
return PyCallExpressionHelper.getArgument(parameter, argClass, this);
}
@Override
public PyExpression getKeywordArgument(String keyword) {
return PyCallExpressionHelper.getKeywordArgument(this, keyword);
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.FunctionParameter;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
@@ -128,6 +129,12 @@ public class PyDecoratorImpl extends StubBasedPsiElementBase<PyDecoratorStub> im
return getArgument(index, argClass);
}
@Nullable
@Override
public <T extends PsiElement> T getArgument(@NotNull final FunctionParameter parameter, @NotNull final Class<T> argClass) {
return PyCallExpressionHelper.getArgument(parameter, argClass, this);
}
@Override
public PyExpression getKeywordArgument(String keyword) {
return PyCallExpressionHelper.getKeywordArgument(this, keyword);