Merge branch 'python-fixes'

This commit is contained in:
Andrey Vlasovskikh
2013-01-22 19:22:12 +04:00
33 changed files with 405 additions and 164 deletions
@@ -2,31 +2,41 @@ package com.jetbrains.python.psi;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.impl.PyQualifiedName;
import com.jetbrains.python.psi.types.PyClassType;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class PyClassRef {
@Nullable
private final PsiElement myElement;
@Nullable
private final String myQName;
@Nullable private final PsiElement myElement;
@Nullable private final String myQName;
@Nullable private final PyClassType myType;
public PyClassRef(@Nullable PsiElement element) {
myElement = element;
myQName = null;
myType = null;
}
public PyClassRef(@Nullable String qName) {
myElement = null;
myQName = qName;
myType = null;
}
public PyClassRef(@Nullable PyClassType type) {
myElement = null;
myQName = null;
myType = type;
}
@Nullable
public PyClass getPyClass() {
return myElement instanceof PyClass ? (PyClass) myElement : null;
if (myElement instanceof PyClass) {
return (PyClass) myElement;
}
return null;
}
@Nullable
@@ -34,26 +44,40 @@ public class PyClassRef {
return myElement;
}
@Nullable
public PyClassType getType() {
return myType;
}
@Nullable
public String getClassName() {
if (myElement instanceof PyClass) {
return ((PyClass)myElement).getName();
}
if (myQName != null) {
else if (myQName != null) {
final PyQualifiedName qname = PyQualifiedName.fromDottedString(myQName);
if (qname != null) {
return qname.getLastComponent();
}
}
else if (myType != null) {
return myType.getName();
}
return null;
}
@Nullable
public String getQualifiedName() {
if (myQName != null) {
if (myElement instanceof PyClass) {
return ((PyClass)myElement).getQualifiedName();
}
else if (myQName != null) {
return myQName;
}
return myElement instanceof PyClass ? ((PyClass)myElement).getQualifiedName() : null;
else if (myType != null) {
return myType.getName();
}
return null;
}
@Override
@@ -27,7 +27,7 @@ public interface PyTypeProvider {
PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context);
@Nullable
PyType getIterationType(PyClass iterable);
PyType getIterationType(@NotNull PyClass iterable);
@Nullable
PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context);
@@ -92,7 +92,7 @@ public class PyTypeProviderBase implements PyTypeProvider {
}
@Override
public PyType getIterationType(PyClass iterable) {
public PyType getIterationType(@NotNull PyClass iterable) {
return null;
}
@@ -59,7 +59,7 @@ public class TypeAssertionIntention implements IntentionAction {
(reference != null && reference.resolve() == null)) {
return false;
}
final PyType type = problemElement.getType(TypeEvalContext.slow());
final PyType type = problemElement.getType(TypeEvalContext.fastStubOnly(file));
return (type == null || type instanceof PyReturnTypeReference);
}
@@ -59,7 +59,7 @@ public abstract class TypeIntention implements IntentionAction {
protected abstract void updateText(boolean isReturn);
private static boolean isTypeUndefined(PyExpression problemElement) {
final PyType type = problemElement.getType(TypeEvalContext.slow());
final PyType type = problemElement.getType(TypeEvalContext.fastStubOnly(problemElement.getContainingFile()));
if (type == null || type instanceof PyReturnTypeReference || type instanceof PyDynamicallyEvaluatedType) {
PsiReference reference = problemElement.getReference();
if (problemElement instanceof PyQualifiedExpression) {
@@ -74,6 +74,9 @@ public abstract class TypeIntention implements IntentionAction {
}
private static boolean isDefinedInAnnotation(PyExpression problemElement, PsiReference reference) {
if (LanguageLevel.forElement(problemElement).isOlderThan(LanguageLevel.PYTHON30)) {
return false;
}
final PsiElement resolved = reference != null? reference.resolve() : null;
PyParameter parameter = getParameter(problemElement, resolved);
@@ -87,7 +90,7 @@ public abstract class TypeIntention implements IntentionAction {
final PsiReference psiReference = callee.getReference();
if (psiReference != null && psiReference.resolve() == null) return false;
}
final Callable callable = ((PyCallExpression)assignedValue).resolveCalleeFunction(PyResolveContext.defaultContext());
final Callable callable = ((PyCallExpression)assignedValue).resolveCalleeFunction(getResolveContext(problemElement));
if (callable instanceof PyFunction && ((PyFunction)callable).getAnnotation() != null) return true;
}
@@ -129,9 +132,10 @@ public abstract class TypeIntention implements IntentionAction {
if (callExpression != null) {
final PyExpression callee = callExpression.getCallee();
if (callee instanceof PyQualifiedExpression) {
final Callable pyFunction = callExpression.resolveCalleeFunction(PyResolveContext.defaultContext());
final TypeEvalContext context = TypeEvalContext.fastStubOnly(callee.getContainingFile());
final Callable pyFunction = callExpression.resolveCalleeFunction(PyResolveContext.defaultContext().withTypeEvalContext(context));
if (pyFunction instanceof PyFunction) {
PyType type = pyFunction.getReturnType(TypeEvalContext.slow(), (PyQualifiedExpression)callee);
PyType type = pyFunction.getReturnType(context, (PyQualifiedExpression)callee);
if (type == null || type instanceof PyReturnTypeReference) {
final PsiReference reference = callee.getReference();
if (reference instanceof PsiPolyVariantReference) {
@@ -187,13 +191,17 @@ public abstract class TypeIntention implements IntentionAction {
protected static Callable getCallable(PsiElement elementAt) {
PyCallExpression callExpression = getCallExpression(elementAt);
if (callExpression != null) {
final Callable callable = callExpression.resolveCalleeFunction(PyResolveContext.defaultContext());
return callable == null? PsiTreeUtil.getParentOfType(elementAt, PyFunction.class) : callable;
if (callExpression != null && elementAt != null) {
final Callable callable = callExpression.resolveCalleeFunction(getResolveContext(elementAt));
return callable == null ? PsiTreeUtil.getParentOfType(elementAt, PyFunction.class) : callable;
}
return PsiTreeUtil.getParentOfType(elementAt, PyFunction.class);
}
private static PyResolveContext getResolveContext(@NotNull PsiElement origin) {
return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(origin.getContainingFile()));
}
public boolean startInWriteAction() {
return true;
}
@@ -49,7 +49,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType
if (myFields.contains(name)) {
return Collections.singletonList(new RatedResolveResult(1000, new PyElementImpl(myDeclaration.getNode())));
}
return Collections.emptyList();
return null;
}
@Override
@@ -11,6 +11,7 @@ import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyQualifiedName;
import com.jetbrains.python.psi.impl.PyTypeProvider;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.NotNull;
@@ -26,8 +27,8 @@ import java.util.Properties;
* @author yole
*/
public class PyStdlibTypeProvider extends PyTypeProviderBase {
private Properties myStdlibTypes2 = new Properties();
private Properties myStdlibTypes3 = new Properties();
@NotNull private Properties myStdlibTypes2 = new Properties();
@NotNull private Properties myStdlibTypes3 = new Properties();
@Nullable
public static PyStdlibTypeProvider getInstance() {
@@ -41,11 +42,29 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
@Override
public PyType getReferenceType(@NotNull PsiElement referenceTarget, @NotNull TypeEvalContext context, @Nullable PsiElement anchor) {
if (referenceTarget instanceof PyFunction &&
PyNames.NAMEDTUPLE.equals(((PyFunction) referenceTarget).getName()) &&
PyNames.COLLECTIONS_PY.equals(referenceTarget.getContainingFile().getName()) &&
anchor instanceof PyCallExpression) {
return PyNamedTupleType.fromCall((PyCallExpression)anchor);
if (referenceTarget instanceof PyTargetExpression) {
final PyTargetExpression target = (PyTargetExpression)referenceTarget;
final PyQualifiedName calleeName = target.getCalleeName();
if (calleeName != null && PyNames.NAMEDTUPLE.equals(calleeName.toString())) {
// TODO: Create stubs for namedtuple for preventing switch from stub to AST
final PyExpression value = target.findAssignedValue();
if (value instanceof PyCallExpression) {
final PyCallExpression call = (PyCallExpression)value;
final PyCallExpression.PyMarkedCallee callee = call.resolveCallee(PyResolveContext.noImplicits());
if (callee != null) {
final Callable callable = callee.getCallable();
if (PyNames.COLLECTIONS_PY.equals(callable.getContainingFile().getName())) {
return PyNamedTupleType.fromCall(call);
}
}
}
}
}
else if (referenceTarget instanceof PyFunction && anchor instanceof PyCallExpression) {
if (PyNames.NAMEDTUPLE.equals(((PyFunction)referenceTarget).getName()) &&
PyNames.COLLECTIONS_PY.equals(referenceTarget.getContainingFile().getName())) {
return PyNamedTupleType.fromCall((PyCallExpression)anchor);
}
}
return null;
}
@@ -115,8 +134,9 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
return null;
}
@Nullable
@Override
public PyType getIterationType(PyClass iterable) {
public PyType getIterationType(@NotNull PyClass iterable) {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(iterable);
if (builtinCache.hasInBuiltins(iterable)) {
if ("file".equals(iterable.getName())) {
@@ -128,7 +148,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
@Nullable
@Override
public PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context) {
public PyType getContextManagerVariableType(@NotNull PyClass contextManager, @NotNull PyExpression withExpression, @NotNull TypeEvalContext context) {
if ("contextlib.closing".equals(contextManager.getQualifiedName()) && withExpression instanceof PyCallExpression) {
PyExpression closee = ((PyCallExpression)withExpression).getArgument(0, PyExpression.class);
if (closee != null) {
@@ -159,18 +179,8 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
}
PyType argType = entry.getKey().getType(context);
// Special case for the 'mode' argument of the 'open()' builtin
if (("__builtin__.open".equals(qname) || "io.open".equals(qname) || "os.fdopen".equals(qname)) && "mode".equals(name)) {
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
final LanguageLevel level = LanguageLevel.forElement(anchor);
argType = cache.getUnicodeType(level);
final PyExpression modeExpr = entry.getKey();
if (modeExpr instanceof PyStringLiteralExpression) {
final String literal = ((PyStringLiteralExpression)modeExpr).getStringValue();
if (literal.contains("b")) {
argType = cache.getBytesType(level);
}
}
}
final PyExpression modeExpr = entry.getKey();
argType = getOpenFunctionType(argType, qname, name, modeExpr, anchor);
final PyType paramType = getParameterTypeByQName(overloadedQName, name, anchor);
if (PyTypeChecker.match(paramType, argType, context)) {
if (argType != null && paramType != null) {
@@ -190,7 +200,29 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
return null;
}
@Nullable PyType getParameterTypeByQName(@NotNull String functionQName, @NotNull String name, @NotNull PsiElement anchor) {
@Nullable
private PyType getOpenFunctionType(@Nullable PyType argType,
@NotNull String callQName,
@NotNull String parameterName,
@NotNull PyExpression modeExpr,
@NotNull PsiElement anchor) {
if (("__builtin__.open".equals(callQName) || "io.open".equals(callQName) || "os.fdopen".equals(callQName)) &&
"mode".equals(parameterName)) {
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
final LanguageLevel level = LanguageLevel.forElement(anchor);
argType = cache.getUnicodeType(level);
if (modeExpr instanceof PyStringLiteralExpression) {
final String literal = ((PyStringLiteralExpression)modeExpr).getStringValue();
if (literal.contains("b")) {
argType = cache.getBytesType(level);
}
}
}
return argType;
}
@Nullable
private PyType getParameterTypeByQName(@NotNull String functionQName, @NotNull String name, @NotNull PsiElement anchor) {
final LanguageLevel level = LanguageLevel.forElement(anchor);
final String key = String.format("Python%d/%s.%s", level.getVersion(), functionQName, name);
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
@@ -212,7 +244,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
}
@Nullable
private StructuredDocString getStructuredDocString(String qualifiedName, LanguageLevel level) {
private StructuredDocString getStructuredDocString(@NotNull String qualifiedName, @NotNull LanguageLevel level) {
final Properties db = getStdlibTypes(level);
final String docString = db.getProperty(qualifiedName);
if (docString == null && level.isPy3K()) { //if we couldn't find for Py3K will search in Python2 db
@@ -246,7 +278,8 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
return result;
}
private Properties getStdlibTypes(LanguageLevel level) {
@NotNull
private Properties getStdlibTypes(@NotNull LanguageLevel level) {
final Properties result = level.isPy3K() ? myStdlibTypes3 : myStdlibTypes2;
final String name = level.isPy3K() ? "StdlibTypes3" : "StdlibTypes2";
if (result.isEmpty()) {
@@ -682,7 +682,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
private static boolean hasUnresolvedAncestors(PyClass cls) {
for (PyClassRef classRef : cls.iterateAncestors()) {
if (classRef.getPyClass() == null) {
if (classRef.getPyClass() == null && classRef.getType() == null) {
return true;
}
}
+14 -20
View File
@@ -9,7 +9,6 @@ import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.lang.ASTFactory;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
@@ -38,6 +37,7 @@ import com.intellij.util.containers.HashSet;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType;
import com.jetbrains.python.documentation.EpydocUtil;
@@ -437,29 +437,23 @@ public class PyUtil {
if (!(target instanceof PyTargetExpression)) {
return false;
}
PyFunction method = PsiTreeUtil.getParentOfType(target, PyFunction.class);
if (method == null || method.getContainingClass() == null) {
return false;
final ScopeOwner owner = ScopeUtil.getScopeOwner(target);
if (owner instanceof PyFunction) {
final PyFunction method = (PyFunction)owner;
if (method.getContainingClass() != null) {
final PyParameter[] params = method.getParameterList().getParameters();
if (params.length > 0) {
final PyTargetExpression targetExpr = (PyTargetExpression)target;
final PyExpression qualifier = targetExpr.getQualifier();
return qualifier != null && qualifier.getText().equals(params[0].getName());
}
}
}
final PyParameter[] params = method.getParameterList().getParameters();
if (params.length == 0) {
return false;
}
final PyTargetExpression targetExpr = (PyTargetExpression)target;
PyExpression qualifier = targetExpr.getQualifier();
return qualifier != null && qualifier.getText().equals(params[0].getName());
return false;
}
public static boolean isClassAttribute(PsiElement element) {
PyAssignmentStatement statement = PsiTreeUtil.getParentOfType(element, PyAssignmentStatement.class);
if (statement == null) {
return false;
}
PyStatementList stmtList = PsiTreeUtil.getParentOfType(statement, PyStatementList.class);
if (stmtList == null || !(stmtList.getParent() instanceof PyClass)) {
return false;
}
return PsiTreeUtil.isAncestor(statement.getLeftHandSideExpression(), element, false);
return element instanceof PyTargetExpression && ScopeUtil.getScopeOwner(element) instanceof PyClass;
}
public static boolean isDocString(PyExpression expression) {
@@ -174,6 +174,9 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress
}
final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, this);
if (providedType != null) {
if (providedType instanceof PyClassType) {
return ((PyClassType)providedType).toInstance();
}
return providedType;
}
if (target instanceof Callable) {
@@ -17,6 +17,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.*;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.PyResolveUtil;
@@ -25,6 +26,7 @@ import com.jetbrains.python.psi.stubs.PropertyStubStorage;
import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyClassTypeImpl;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
@@ -147,20 +149,21 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
final PyExpression[] superExpressions = getSuperClassExpressions();
List<PsiElement> superClasses = new ArrayList<PsiElement>();
for (PyExpression expr : superExpressions) {
expr = unfoldClass(expr);
if (expr instanceof PyReferenceExpression) {
final PsiPolyVariantReference ref = ((PyReferenceExpression)expr).getReference(PyResolveContext.noProperties());
if (ref != null) {
final PsiElement result = ref.resolve();
if (result != null) {
superClasses.add(result);
}
}
}
superClasses.add(classElementFromExpression(expr));
}
return PsiUtilCore.toPsiElementArray(superClasses);
}
@Nullable
public static PsiElement classElementFromExpression(@NotNull PyExpression expression) {
expression = unfoldClass(expression);
if (expression instanceof PyReferenceExpression) {
final PsiPolyVariantReference ref = ((PyReferenceExpression)expression).getReference(PyResolveContext.noProperties());
return ref.resolve();
}
return null;
}
public static PyExpression unfoldClass(PyExpression expression) {
if (expression instanceof PyCallExpression) {
PyCallExpression call = (PyCallExpression)expression;
@@ -205,7 +208,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
}
public PyDecoratorList getDecoratorList() {
return childToPsi(PyElementTypes.DECORATOR_LIST);
return getStubOrPsiChild(PyElementTypes.DECORATOR_LIST);
}
@Nullable
@@ -265,9 +268,22 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
List<PyClassRef> result = resolveSuperClassesFromStub();
if (result == null) {
result = new ArrayList<PyClassRef>();
PsiElement[] superClassElements = getSuperClassElements();
for (PsiElement element : superClassElements) {
result.add(new PyClassRef(element));
final TypeEvalContext context = TypeEvalContext.fastStubOnly(null);
final PyExpression[] superClassExpressions = getSuperClassExpressions();
for (PyExpression expression : superClassExpressions) {
final PsiElement element = classElementFromExpression(expression);
if (element != null) {
result.add(new PyClassRef(element));
}
else {
final PyType type = expression.getType(context);
if (type instanceof PyClassType) {
result.add(new PyClassRef((PyClassType)type));
}
else {
result.add(new PyClassRef((PsiElement)null));
}
}
}
}
@@ -1078,7 +1094,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
@NotNull
@Override
public SearchScope getUseScope() {
final ScopeOwner scopeOwner = PsiTreeUtil.getParentOfType(this, ScopeOwner.class);
final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(this);
if (scopeOwner instanceof PyFunction) {
return new LocalSearchScope(scopeOwner);
}
@@ -21,6 +21,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDocStringFinder;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.documentation.StructuredDocString;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
@@ -202,7 +203,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
@Nullable
private PyType getGenericReturnType(@NotNull TypeEvalContext typeEvalContext, @Nullable PyQualifiedExpression callSite) {
if (typeEvalContext.maySwitchToAST(this)) {
if (typeEvalContext.maySwitchToAST(this) && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) {
PyAnnotation anno = getAnnotation();
if (anno != null) {
PyClass pyClass = anno.resolveToClass();
@@ -505,7 +506,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
@NotNull
@Override
public SearchScope getUseScope() {
final ScopeOwner scopeOwner = PsiTreeUtil.getParentOfType(this, ScopeOwner.class);
final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(this);
if (scopeOwner instanceof PyFunction) {
return new LocalSearchScope(scopeOwner);
}
@@ -55,9 +55,7 @@ public class PyImportElementImpl extends PyBaseElementImpl<PyImportElementStub>
}
public PyTargetExpression getAsNameElement() {
final ASTNode asNameNode = getNode().findChildByType(PyElementTypes.TARGET_EXPRESSION);
if (asNameNode == null) return null;
return (PyTargetExpression)asNameNode.getPsi();
return getStubOrPsiChild(PyElementTypes.TARGET_EXPRESSION);
}
public String getAsName() {
@@ -404,29 +404,6 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
return null;
}
private static PsiElement transitiveResolve(PsiElement element) {
PsiElement prev = null;
while (element != prev) {
prev = element;
PsiReference ref = element.getReference();
if (ref != null) {
PsiElement e = ref.resolve();
if (e != null) {
element = e;
}
}
}
return element;
}
private static boolean isGlobal(PsiElement anchor, String name) {
final ScopeOwner owner = ScopeUtil.getDeclarationScopeOwner(anchor, name);
if (owner != null) {
return ControlFlowCache.getScope(owner).isGlobal(name);
}
return false;
}
public boolean isReferenceTo(PsiElement element) {
if (element instanceof PsiFileSystemItem) {
// may be import via alias, so don't check if names match, do simple resolve check instead
@@ -454,10 +431,6 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
final String elementName = ((PsiNamedElement)element).getName();
if ((Comparing.equal(myElement.getReferencedName(), elementName) || PyNames.INIT.equals(elementName))) {
if (!haveQualifiers(element)) {
// Global elements may in fact be resolved to their outer declarations
if (isGlobal(element, elementName)) {
element = transitiveResolve(element);
}
final ScopeOwner ourScopeOwner = ScopeUtil.getScopeOwner(getElement());
final ScopeOwner theirScopeOwner = ScopeUtil.getScopeOwner(element);
// TODO: Cython-dependent code without CythonLanguageDialect.isInsideCythonFile() check
@@ -468,7 +441,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
}
}
final PsiElement resolveResult = (isGlobal(getElement(), elementName)) ? transitiveResolve(getElement()) : resolve();
final PsiElement resolveResult = resolve();
if (resolveResult == element) {
return true;
}
@@ -535,15 +508,16 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
private boolean resolvesToSameGlobal(PsiElement element, String elementName, ScopeOwner ourScopeOwner, ScopeOwner theirScopeOwner,
PsiElement resolveResult) {
// Handle situations when there is no top-level declaration for globals and transitive resolve doesn't help
final boolean ourIsGlobal = ControlFlowCache.getScope(ourScopeOwner).isGlobal(elementName);
final boolean theirIsGlobal = ControlFlowCache.getScope(theirScopeOwner).isGlobal(elementName);
final PsiFile ourFile = getElement().getContainingFile();
final PsiFile theirFile = element.getContainingFile();
if (ourIsGlobal && theirIsGlobal && ourFile == theirFile) {
return true;
if (ourFile == theirFile) {
final boolean ourIsGlobal = ControlFlowCache.getScope(ourScopeOwner).isGlobal(elementName);
final boolean theirIsGlobal = ControlFlowCache.getScope(theirScopeOwner).isGlobal(elementName);
if (ourIsGlobal && theirIsGlobal) {
return true;
}
}
if (theirIsGlobal && ScopeUtil.getScopeOwner(resolveResult) == ourFile) {
if (ScopeUtil.getScopeOwner(resolveResult) == ourFile && ControlFlowCache.getScope(theirScopeOwner).isGlobal(elementName)) {
return true;
}
return false;
@@ -54,7 +54,7 @@ public class CompletionVariantsProcessor extends VariantsProcessor {
final String params = StringUtil.join(parameterList.getParameters(), new Function<PyParameter, String>() {
@Override
public String fun(PyParameter pyParameter) {
return pyParameter.getText();
return pyParameter.getName();
}
}, ", ");
item = item.withTailText("(" + params + ")");
@@ -11,6 +11,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiInvalidElementAccessException;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
@@ -156,23 +157,25 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
for (PyClassRef superClass : myClass.iterateAncestors()) {
final PyClass pyClass = superClass.getPyClass();
final PsiElement element = superClass.getElement();
final PyClassType type = superClass.getType();
if (pyClass != null) {
PsiElement superMember = resolveClassMember(pyClass, myIsDefinition, name, null);
if (superMember != null) {
return ResolveResultList.to(superMember);
}
}
else {
final PsiElement element = superClass.getElement();
if (element != null) {
for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
final PyType refType = typeProvider.getReferenceType(element, resolveContext.getTypeEvalContext(), myClass);
if (refType != null) {
return refType.resolveMember(name, location, direction, resolveContext);
}
else if (element != null) {
for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
final PyType refType = typeProvider.getReferenceType(element, resolveContext.getTypeEvalContext(), myClass);
if (refType != null) {
return refType.resolveMember(name, location, direction, resolveContext);
}
}
}
else if (type != null) {
return type.resolveMember(name, location, direction, resolveContext);
}
}
if (isDefinition() && myClass.isNewStyleClass()) {
PyClassType typeType = getMetaclassType();
@@ -209,13 +212,9 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
private PyClassType getMetaclassType() {
final PyTargetExpression metaClassAttribute = myClass.findClassAttribute(PyNames.DUNDER_METACLASS, true);
if (metaClassAttribute != null) {
final PyExpression metaclass = metaClassAttribute.findAssignedValue();
if (metaclass instanceof PyReferenceExpression) {
final QualifiedResolveResult result = ((PyReferenceExpression)metaclass).followAssignmentsChain(PyResolveContext.noImplicits());
PsiElement element = result.getElement();
if (element instanceof PyClass) {
return new PyClassTypeImpl((PyClass)element, false);
}
final PyType type = metaClassAttribute.getType(TypeEvalContext.fastStubOnly(null));
if (type instanceof PyClassType) {
return (PyClassType)type;
}
}
return PyBuiltinCache.getInstance(myClass).getObjectType("type");
@@ -371,16 +370,33 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
Set<String> namesAlready,
ProcessingContext context,
List<Object> ret) {
for (PyClass ancestor : myClass.getSuperClasses()) {
Object[] ancestry = (new PyClassTypeImpl(ancestor, myIsDefinition)).getCompletionVariants(name, expressionHook, context);
for (Object ob : ancestry) {
String inheritedName = ob.toString();
if (!namesAlready.contains(inheritedName) && !isClassPrivate(inheritedName)) {
ret.add(ob);
namesAlready.add(inheritedName);
for (PyExpression expression : myClass.getSuperClassExpressions()) {
final PsiReference reference = expression.getReference();
PsiElement element = null;
if (reference != null) {
element = reference.resolve();
}
PyType type;
if (element instanceof PyClass) {
type = new PyClassTypeImpl((PyClass)element, myIsDefinition);
}
else {
type = expression.getType(TypeEvalContext.fastStubOnly(myClass.getContainingFile()));
if (type instanceof PyClassType && !myIsDefinition) {
type = ((PyClassType)type).toInstance();
}
}
ContainerUtil.addAll(ret, ancestry);
if (type != null) {
Object[] ancestry = type.getCompletionVariants(name, expressionHook, context);
for (Object ob : ancestry) {
String inheritedName = ob.toString();
if (!namesAlready.contains(inheritedName) && !isClassPrivate(inheritedName)) {
ret.add(ob);
namesAlready.add(inheritedName);
}
}
ContainerUtil.addAll(ret, ancestry);
}
}
}
@@ -148,7 +148,7 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator<Pep8ExternalAnnotat
}
if (problemElement != null) {
final Annotation annotation;
final String message = "PEP8: " + problem.myDescription;
final String message = "PEP 8: " + problem.myDescription;
if (annotationResult.level == HighlightDisplayLevel.ERROR) {
annotation = holder.createErrorAnnotation(problemElement, message);
}
@@ -0,0 +1,10 @@
from collections import namedtuple
class C(namedtuple('Coord', 'latitude longitude')):
def foo(self):
return -1
c = C()
c.latitude
@@ -0,0 +1,10 @@
from collections import namedtuple
class C(namedtuple('Coord', 'latitude longitude')):
def foo(self):
return -1
c = C()
c.lat<caret>
@@ -0,0 +1,14 @@
class A(object):
def foo(self):
pass
C = A
class B(C):
pass
b = B()
b.foo() #pass
@@ -1,15 +0,0 @@
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'], verbose=True)
print Point.x, Point.y
p = Point(11, y=22)
print p.x + p.y
print p.__add__
print p._asdict()
print Point._fields
print p._replace
if isinstance(p, Point):
p.x
@@ -0,0 +1,5 @@
class C(<error descr="Unresolved reference 'B'">B</error>):
pass
c = C()
c.foo()
@@ -0,0 +1,4 @@
from b import Foo
foo = Foo()
print(foo.bar, foo.<warning descr="Unresolved attribute reference 'baz' for class 'Foo'">baz</warning>)
@@ -0,0 +1,4 @@
from collections import namedtuple
Foo = namedtuple('Foo', 'bar spam')
@@ -0,0 +1,4 @@
from b import Bar
bar = Bar()
print(bar.eggs, bar.<warning descr="Unresolved attribute reference 'bacon' for class 'Bar'">bacon</warning>)
@@ -0,0 +1,5 @@
from collections import namedtuple
class Bar(namedtuple('Bar', 'spam eggs')):
pass
@@ -0,0 +1,22 @@
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'], verbose=True)
print(Point.x, Point.y)
p = Point(11, y=22)
print(p.x + p.y + p.<warning descr="Unresolved attribute reference 'z' for class 'Point'">z</warning>)
print(p.__add__)
print(p._asdict())
print(Point._fields)
print(p._replace)
if isinstance(p, Point):
p.x
class C(namedtuple('C', 'x y')):
def f(self):
return self
c = C()
print(c.x, c.y, c.<warning descr="Unresolved attribute reference 'z' for class 'C'">z</warning>, c.f())
@@ -0,0 +1,21 @@
foo = []
def f1():
global foo
foo = [1, 2, 3]
def f2(x):
global foo
foo = foo + [x]
if 1 in foo:
return f<caret>oo
def f3(x):
return foo + [x]
def f4(x):
global foo
return foo + [x]
def f5(foo):
return foo
@@ -0,0 +1,21 @@
bar = []
def f1():
global bar
bar = [1, 2, 3]
def f2(x):
global bar
bar = bar + [x]
if 1 in bar:
return bar
def f3(x):
return bar + [x]
def f4(x):
global bar
return bar + [x]
def f5(foo):
return foo
@@ -33,6 +33,10 @@ public class Py3CompletionTest extends PyTestCase {
assertTrue(strings.contains("long"));
}
public void testNamedTupleBaseClass() {
doTest();
}
private void doTest() {
CamelHumpMatcher.forceStartMatching(getTestRootDisposable());
final String testName = "completion/" + getTestName(true);
@@ -0,0 +1,55 @@
package com.jetbrains.python.inspections;
import com.intellij.testFramework.LightProjectDescriptor;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NotNull;
/**
* @author vlan
*/
public class Py3UnresolvedReferencesInspectionTest extends PyTestCase {
private static final String TEST_DIRECTORY = "inspections/PyUnresolvedReferencesInspection3K/";
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return ourPy3Descriptor;
}
private void doTest() {
runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() {
@Override
public void run() {
myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py");
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.checkHighlighting(true, false, false);
}
});
}
private void doMultiFileTest(@NotNull final String filename) {
runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() {
@Override
public void run() {
final String testName = getTestName(false);
myFixture.copyDirectoryToProject(TEST_DIRECTORY + testName, "");
myFixture.configureFromTempProjectFile(filename);
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.checkHighlighting(true, false, false);
}
});
}
public void testNamedTuple() {
doTest();
}
public void testNamedTupleAssignment() {
doMultiFileTest("a.py");
}
// TODO: Currently there are no stubs for namedtuple() in the base classes list and no indicators for forcing stub->AST
public void _testNamedTupleBaseStub() {
doMultiFileTest("a.py");
}
}
@@ -58,10 +58,6 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase {
doTest();
}
public void testNamedTuple() {
doTest();
}
// PY-2308
public void testTypeAssertions() {
doTest();
@@ -231,6 +227,16 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase {
doTest();
}
// PY-7301
public void testUnresolvedBaseClass() {
doTest();
}
// PY-5427
public void testBaseClassAssignment() {
doTest();
}
private void doTest() {
myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py");
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
@@ -71,10 +71,14 @@ public class PyRenameTest extends PyTestCase {
doTest("Shazam");
}
public void testRenameGlobal() {
doTest("bar");
}
public void testRenameGlobalWithoutToplevel() { // PY-3547
doTest("bar");
}
public void testRenameSlots() { // PY-4195
doTest("bacon");
}