PY-12579 "url" function is not processed correctly when imported as alias

This commit is contained in:
Ilya.Kazakevich
2014-03-31 18:35:27 +04:00
parent dd5dab3dcc
commit 76e04ecd2c
5 changed files with 49 additions and 29 deletions
@@ -2,11 +2,15 @@ package com.jetbrains.python.nameResolver;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.util.ArrayUtil;
import com.jetbrains.python.psi.PyElement;
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;
/**
* @author Ilya.Kazakevich
*/
@@ -18,11 +22,11 @@ public final class NameResolverTools {
/**
* Checks if FQ element name is one of provided names
*
* @param element element to check
* @param namesProvider some enum that has one or more names
* @param element element to check
* @param namesProviders some enum that has one or more names
* @return true if element's fqn is one of names, provided by provider
*/
public static boolean isName(@NotNull final PyElement element, @NotNull final FQNamesProvider namesProvider) {
public static boolean isName(@NotNull final PyElement element, @NotNull final FQNamesProvider... namesProviders) {
PyElement elementToCheck = element;
final PsiReference reference = element.getReference();
if (reference != null) {
@@ -33,8 +37,22 @@ public final class NameResolverTools {
}
if (elementToCheck instanceof PyQualifiedNameOwner) {
final String qualifiedName = ((PyQualifiedNameOwner)elementToCheck).getQualifiedName();
return ArrayUtil.contains(qualifiedName, namesProvider.getNames());
return getNames(namesProviders).contains(qualifiedName);
}
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;
}
}
@@ -115,10 +115,10 @@ public interface PyCallExpression extends PyExpression {
/**
* Checks if the qualified name of the callee matches any of the specified names provided by provider.
* @see com.jetbrains.python.nameResolver
* @param name provider that provides one or more names to check
* @param name providers that provides one or more names to check
* @return true if matches, false otherwise
*/
boolean isCallee(@NotNull FQNamesProvider name);
boolean isCallee(@NotNull FQNamesProvider... name);
/**
* Couples function with a flag describing the way it is called.
@@ -47,7 +47,8 @@ public class PyCallExpressionHelper {
/**
* TODO: Copy/Paste with {@link com.jetbrains.python.psi.PyArgumentList#addArgument(com.jetbrains.python.psi.PyExpression)}
* Adds an argument to the end of argument list.
* @param us the arg list
*
* @param us the arg list
* @param expression what to add
*/
public static void addArgument(PyCallExpression us, PyExpression expression) {
@@ -60,7 +61,7 @@ public class PyCallExpressionHelper {
* Tries to interpret a call as a call to built-in {@code classmethod} or {@code staticmethod}.
*
* @param redefiningCall the possible call, generally a result of chasing a chain of assignments
* @param us any in-project PSI element, used to determine SDK and ultimately builtins module used to check the wrapping functions
* @param us any in-project PSI element, used to determine SDK and ultimately builtins module used to check the wrapping functions
* @return a pair of wrapper name and wrapped function; for {@code staticmethod(foo)} it would be ("staticmethod", foo).
*/
@Nullable
@@ -117,8 +118,8 @@ public class PyCallExpressionHelper {
return (PyClass)resolved;
}
else if (resolved instanceof PyFunction) {
final PyFunction pyFunction = (PyFunction) resolved;
return pyFunction.getContainingClass();
final PyFunction pyFunction = (PyFunction)resolved;
return pyFunction.getContainingClass();
}
return null;
@@ -148,11 +149,11 @@ public class PyCallExpressionHelper {
}
}
if (resolved instanceof Callable) {
return (Callable) resolved;
return (Callable)resolved;
}
return null;
}
@Nullable
public static PyCallExpression.PyMarkedCallee resolveCallee(PyCallExpression us, PyResolveContext resolveContext) {
@@ -211,19 +212,19 @@ public class PyCallExpressionHelper {
}
if (resolved instanceof Callable) {
PyFunction.Modifier modifier = resolved instanceof PyFunction
? ((PyFunction)resolved).getModifier()
: null;
? ((PyFunction)resolved).getModifier()
: null;
if (modifier == null && wrappedModifier != null) {
modifier = wrappedModifier;
}
boolean isByInstance = isConstructorCall || isQualifiedByInstance((Callable)resolved, qualifiers, context)
|| resolved instanceof PyBoundFunction;
PyExpression lastQualifier = qualifiers != null && qualifiers.isEmpty() ? null : qualifiers.get(qualifiers.size()-1);
PyExpression lastQualifier = qualifiers != null && qualifiers.isEmpty() ? null : qualifiers.get(qualifiers.size() - 1);
boolean isByClass = lastQualifier == null ? false : isQualifiedByClass((Callable)resolved, lastQualifier, context);
final Callable callable = (Callable)resolved;
implicitOffset += getImplicitArgumentCount(callable, modifier, isConstructorCall, isByInstance, isByClass);
implicitOffset = implicitOffset < 0? 0: implicitOffset; // wrong source can trigger strange behaviour
implicitOffset = implicitOffset < 0 ? 0 : implicitOffset; // wrong source can trigger strange behaviour
return new PyCallExpression.PyMarkedCallee(callable, modifier, implicitOffset,
resolveResult != null ? resolveResult.isImplicit() : false);
}
@@ -256,11 +257,11 @@ public class PyCallExpressionHelper {
/**
* Finds how many arguments are implicit in a given call.
*
* @param callable resolved method which is being called; non-methods immediately return 0.
* @param flags set of flags for the call
* @param isByInstance true if the call is known to be by instance (not by class).
* @param callable resolved method which is being called; non-methods immediately return 0.
* @param flags set of flags for the call
* @param isByInstance true if the call is known to be by instance (not by class).
* @return a non-negative number of parameters that are implicit to this call. E.g. for a typical method call 1 is returned
* because one parameter ('self') is implicit.
* because one parameter ('self') is implicit.
*/
private static int getImplicitArgumentCount(
Callable callable,
@@ -451,7 +452,7 @@ public class PyCallExpressionHelper {
}
final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, call);
if (providedType instanceof PyCallableType) {
return ((PyCallableType) providedType).getCallType(context, (PyReferenceExpression)callee);
return ((PyCallableType)providedType).getCallType(context, (PyReferenceExpression)callee);
}
if (target instanceof Callable) {
final Callable callable = (Callable)target;
@@ -571,13 +572,14 @@ public class PyCallExpressionHelper {
/**
* Checks if expression callee's name matches one of names, provided by appropriate {@link com.jetbrains.python.nameResolver.FQNamesProvider}
* @see com.jetbrains.python.nameResolver
* @param expression call expression
* @param namesProvider name provider to check name against
*
* @param expression call expression
* @param namesProviders name providers to check name against
* @return true if matches
* @see com.jetbrains.python.nameResolver
*/
public static boolean isCallee(@NotNull final PyCallExpression expression, @NotNull final FQNamesProvider namesProvider) {
public static boolean isCallee(@NotNull final PyCallExpression expression, @NotNull final FQNamesProvider... namesProviders) {
final PyExpression callee = expression.getCallee();
return (callee != null) && NameResolverTools.isName(callee, namesProvider);
return (callee != null) && NameResolverTools.isName(callee, namesProviders);
}
}
@@ -100,7 +100,7 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress
}
@Override
public boolean isCallee(@NotNull final FQNamesProvider name) {
public boolean isCallee(@NotNull final FQNamesProvider... name) {
return PyCallExpressionHelper.isCallee(this, name);
}
@@ -160,7 +160,7 @@ public class PyDecoratorImpl extends StubBasedPsiElementBase<PyDecoratorStub> im
}
@Override
public boolean isCallee(@NotNull final FQNamesProvider name) {
public boolean isCallee(@NotNull final FQNamesProvider... name) {
return PyCallExpressionHelper.isCallee(this, name);
}