mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'python-fixes'
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
+4
@@ -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>)
|
||||
+4
@@ -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);
|
||||
|
||||
+55
@@ -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");
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user