test fix: context passed to event more methods, PyClassImpl getSuperClasses fix

This commit is contained in:
Ilya.Kazakevich
2015-11-09 20:33:02 +03:00
parent 0654fd6d42
commit fb0520533d
48 changed files with 174 additions and 142 deletions
@@ -125,7 +125,7 @@ public abstract class PyPsiPath {
return ((PyFile) parent).findTopLevelFunction(myFunctionName);
}
if (parent instanceof PyClass) {
return ((PyClass) parent).findMethodByName(myFunctionName, false);
return ((PyClass) parent).findMethodByName(myFunctionName, false, null);
}
for (PsiElement element : parent.getChildren()) {
if (element instanceof PyFunction && myFunctionName.equals(((PyFunction)element).getName())) {
@@ -189,7 +189,7 @@ public abstract class PyPsiPath {
if (!(parent instanceof PyClass)) {
return null;
}
return ((PyClass)parent).findClassAttribute(myAttributeName, true);
return ((PyClass)parent).findClassAttribute(myAttributeName, true, null);
}
}
@@ -121,10 +121,11 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine
*
* @param name what to look for
* @param inherited true: search in superclasses; false: only look for methods defined in this class.
* @param context
* @return
*/
@Nullable
PyFunction findMethodByName(@Nullable @NonNls final String name, boolean inherited);
PyFunction findMethodByName(@Nullable @NonNls final String name, boolean inherited, TypeEvalContext context);
/**
* Finds either __init__ or __new__, whichever is defined for given class.
@@ -193,7 +194,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine
List<PyTargetExpression> getClassAttributesInherited(@NotNull TypeEvalContext context);
@Nullable
PyTargetExpression findClassAttribute(@NotNull String name, boolean inherited);
PyTargetExpression findClassAttribute(@NotNull String name, boolean inherited, TypeEvalContext context);
/**
* Effectively collects assignments to attributes of {@code self} in {@code __init__}, {@code __new__} and
@@ -67,7 +67,7 @@ public class PyQualifiedNameProvider implements QualifiedNameProvider {
final String memberName = StringUtil.getShortName(fqn, '#');
final PyClass nestedClass = aClass.findNestedClass(memberName, false);
if (nestedClass != null) return nestedClass;
final PyFunction methodByName = aClass.findMethodByName(memberName, false);
final PyFunction methodByName = aClass.findMethodByName(memberName, false, null);
if (methodByName != null) return methodByName;
}
}
@@ -86,7 +86,7 @@ public class PyGotoSuperHandler implements CodeInsightActionHandler {
}
final List<PyTargetExpression> result = new ArrayList<PyTargetExpression>();
for (PyClass aClass: pyClass.getAncestorClasses(null)) {
final PyTargetExpression superAttr = aClass.findClassAttribute(name, false);
final PyTargetExpression superAttr = aClass.findClassAttribute(name, false, null);
if (superAttr != null) {
result.add(superAttr);
}
@@ -101,7 +101,7 @@ public class PyGotoSuperHandler implements CodeInsightActionHandler {
}
final List<PyFunction> result = new ArrayList<PyFunction>();
for (PyClass aClass: pyClass.getAncestorClasses(null)) {
final PyFunction byName = aClass.findMethodByName(name, false);
final PyFunction byName = aClass.findMethodByName(name, false, null);
if (byName != null) {
result.add(byName);
}
@@ -92,7 +92,7 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator
builder.append("Has overridden methods");
return false;
}
if (pyClass.findMethodByName(pyFunction.getName(), false) != null) {
if (pyClass.findMethodByName(pyFunction.getName(), false, null) != null) {
builder.append("<br>&nbsp;&nbsp;").append(pyClass.getName());
}
return true;
@@ -126,7 +126,7 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator
PyClass containingClass = PsiTreeUtil.getParentOfType(elt, PyClass.class);
if (containingClass != null && elt instanceof PyTargetExpression) {
for (PyClass ancestor : containingClass.getAncestorClasses(null)) {
final PyTargetExpression attribute = ancestor.findClassAttribute(((PyTargetExpression)elt).getReferencedName(), false);
final PyTargetExpression attribute = ancestor.findClassAttribute(((PyTargetExpression)elt).getReferencedName(), false, null);
if (attribute != null) {
result.add(attribute);
}
@@ -180,7 +180,7 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator
if (PyNames.INIT.equals(function.getName())) {
return null;
}
final TypeEvalContext context = TypeEvalContext.codeAnalysis(element.getProject(), null);
final TypeEvalContext context = TypeEvalContext.codeAnalysis(element.getProject(), (function != null ? function.getContainingFile() : null));
final PsiElement superMethod = PySuperMethodsSearch.search(function, context).findFirst();
if (superMethod != null) {
PyClass superClass = null;
@@ -206,7 +206,7 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator
if (containingClass == null) return null;
for (PyClass ancestor : containingClass
.getAncestorClasses(TypeEvalContext.codeAnalysis(element.getProject(), element.getContainingFile()))) {
final PyTargetExpression ancestorAttr = ancestor.findClassAttribute(name, false);
final PyTargetExpression ancestorAttr = ancestor.findClassAttribute(name, false, null);
if (ancestorAttr != null) {
return new LineMarkerInfo<PsiElement>(element, element.getTextRange().getStartOffset(),
AllIcons.Gutter.OverridingMethod, Pass.UPDATE_ALL,
@@ -254,7 +254,7 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator
public boolean process(final PyClass inheritor) {
for (Iterator<PyFunction> it = candidates.get(pyClass).iterator(); it.hasNext(); ) {
PyFunction func = it.next();
if (inheritor.findMethodByName(func.getName(), false) != null) {
if (inheritor.findMethodByName(func.getName(), false, null) != null) {
overridden.add(func);
it.remove();
}
@@ -115,7 +115,7 @@ public class PyOverrideImplementUtil {
if (name == null || PyUtil.isClassPrivateName(name)) {
continue;
}
if (pyClass.findMethodByName(name, false) == null) {
if (pyClass.findMethodByName(name, false, null) == null) {
final PyMethodMember member = new PyMethodMember(function);
elements.add(member);
}
@@ -245,7 +245,7 @@ public class PyOverrideImplementUtil {
if (!PyNames.INIT.equals(baseFunction.getName()) && context.getReturnType(baseFunction) != PyNoneType.INSTANCE || overridingNew) {
statementBody.append("return ");
}
if (baseClass.isNewStyleClass(null)) {
if (baseClass.isNewStyleClass(context)) {
statementBody.append(PyNames.SUPER);
statementBody.append("(");
final LanguageLevel langLevel = ((PyFile)pyClass.getContainingFile()).getLanguageLevel();
@@ -60,7 +60,7 @@ public class PyUserSkeletonsClassMembersProvider extends PyClassMembersProviderB
}
public static PsiElement findClassMember(@NotNull PyClass cls, @NotNull String name, boolean isDefinition) {
final PyFunction function = cls.findMethodByName(name, false);
final PyFunction function = cls.findMethodByName(name, false, null);
if (function != null) {
final PyUtil.MethodFlags methodFlags = PyUtil.MethodFlags.of(function);
final boolean instanceMethod = methodFlags == null || methodFlags.isInstanceMethod();
@@ -74,7 +74,7 @@ public class PyUserSkeletonsClassMembersProvider extends PyClassMembersProviderB
return instanceAttribute;
}
}
final PyTargetExpression classAttribute = cls.findClassAttribute(name, false);
final PyTargetExpression classAttribute = cls.findClassAttribute(name, false, null);
if (classAttribute != null) {
return classAttribute;
}
@@ -359,7 +359,7 @@ public class PyDocumentationBuilder {
isFromClass = true;
}
else {
inherited = ancestor.findMethodByName(methodName, false);
inherited = ancestor.findMethodByName(methodName, false, null);
}
if (inherited != null) {
docstringElement = inherited.getDocStringExpression();
@@ -403,7 +403,7 @@ public class PyDocumentationBuilder {
final PyClassType objectType = PyBuiltinCache.getInstance(fun).getObjectType(); // old- and new-style classes share the __xxx__ stuff
if (objectType != null) {
final PyClass objectClass = objectType.getPyClass();
final PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false);
final PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false, null);
if (predefinedMethod != null) {
final PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
final String predefinedDoc = predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
@@ -58,7 +58,7 @@ public class DocStringParameterReference extends PsiReferenceBase<PyStringLitera
return resolveParameter((PyFunction)owner);
}
if (owner instanceof PyClass) {
final PyFunction init = ((PyClass)owner).findMethodByName(PyNames.INIT, false);
final PyFunction init = ((PyClass)owner).findMethodByName(PyNames.INIT, false, null);
if (init != null) {
PsiElement element = resolveParameter(init);
if (element == null && (myType.equals(ReferenceType.CLASS_VARIABLE) ||
@@ -39,7 +39,7 @@ public class PyClassFindUsagesHandler extends FindUsagesHandler {
@NotNull
@Override
public PsiElement[] getSecondaryElements() {
final PyFunction initMethod = myClass.findMethodByName(PyNames.INIT, false);
final PyFunction initMethod = myClass.findMethodByName(PyNames.INIT, false, null);
if (initMethod != null) {
return new PsiElement[] { initMethod };
}
@@ -102,8 +102,8 @@ public class PyAbstractClassInspection extends PyInspection {
private static boolean isAbstractMethodForClass(@NotNull PyFunction method, @NotNull PyClass cls) {
final String methodName = method.getName();
if (methodName == null ||
cls.findMethodByName(methodName, false) != null ||
cls.findClassAttribute(methodName, false) != null) {
cls.findMethodByName(methodName, false, null) != null ||
cls.findClassAttribute(methodName, false, null) != null) {
return false;
}
return PyUtil.isDecoratedAsAbstract(method) || PyOverrideImplementUtil.raisesNotImplementedError(method);
@@ -82,12 +82,12 @@ public class PyAttributeOutsideInitInspection extends PyInspection {
attributesInInit.put(classAttr.getName(), classAttr);
}
final PyFunction initMethod = containingClass.findMethodByName(PyNames.INIT, false);
final PyFunction initMethod = containingClass.findMethodByName(PyNames.INIT, false, null);
if (initMethod != null) {
PyClassImpl.collectInstanceAttributes(initMethod, attributesInInit);
}
for (PyClass superClass : containingClass.getAncestorClasses(myTypeEvalContext)) {
final PyFunction superInit = superClass.findMethodByName(PyNames.INIT, false);
final PyFunction superInit = superClass.findMethodByName(PyNames.INIT, false, null);
if (superInit != null)
PyClassImpl.collectInstanceAttributes(superInit, attributesInInit);
@@ -63,7 +63,7 @@ public class PyInitNewSignatureInspection extends PyInspection {
if (cls == null) return;
if (!cls.isNewStyleClass(null)) return;
final String complementaryName = PyNames.NEW.equals(functionName) ? PyNames.INIT : PyNames.NEW;
final PyFunction complementaryMethod = cls.findMethodByName(complementaryName, true);
final PyFunction complementaryMethod = cls.findMethodByName(complementaryName, true, null);
if (complementaryMethod == null || PyUtil.isObjectClass(assertNotNull(complementaryMethod.getContainingClass()))) return;
if (!PyUtil.isSignatureCompatibleTo(complementaryMethod, node, myTypeEvalContext) &&
!PyUtil.isSignatureCompatibleTo(node, complementaryMethod, myTypeEvalContext) &&
@@ -64,7 +64,7 @@ public class PyMissingConstructorInspection extends PyInspection {
return;
if (!superHasConstructor(node)) return;
PyFunction initMethod = node.findMethodByName(INIT, false);
PyFunction initMethod = node.findMethodByName(INIT, false, null);
if (initMethod != null) {
if (isExceptionClass(node, myTypeEvalContext) || hasConstructorCall(node, initMethod)) {
return;
@@ -81,7 +81,7 @@ public class PyMissingConstructorInspection extends PyInspection {
final String className = cls.getName();
for (PyClass c : cls.getAncestorClasses(myTypeEvalContext)) {
final String name = c.getName();
if (!PyUtil.isObjectClass(c) && !Comparing.equal(className, name) && c.findMethodByName(INIT, false) != null) {
if (!PyUtil.isObjectClass(c) && !Comparing.equal(className, name) && c.findMethodByName(INIT, false, null) != null) {
return true;
}
}
@@ -87,7 +87,7 @@ public class PyPropertyAccessInspection extends PyInspection {
property = myPropertyCache.get(key);
}
else {
property = cls.findProperty(name, true, null);
property = cls.findProperty(name, true, myTypeEvalContext);
}
myPropertyCache.put(key, property); // we store nulls, too, to know that a property does not exist
if (property != null) {
@@ -92,9 +92,9 @@ public class PyPropertyDefinitionInspection extends PyInspection {
// reference signatures
PyClass objectClass = builtins.getClass("object");
if (objectClass != null) {
final PyFunction methodRepr = objectClass.findMethodByName("__repr__", false);
final PyFunction methodRepr = objectClass.findMethodByName("__repr__", false, null);
if (methodRepr != null) myOneParamFunction = methodRepr;
final PyFunction methodDelattr = objectClass.findMethodByName("__delattr__", false);
final PyFunction methodDelattr = objectClass.findMethodByName("__delattr__", false, null);
if (methodDelattr != null) myTwoParamFunction = methodDelattr;
}
}
@@ -404,7 +404,7 @@ public class PyStringFormatInspection extends PyInspection {
else {
final PyClassType type = as(myTypeEvalContext.getType(rightExpression), PyClassType.class);
if (type != null) {
if (myUsedMappingKeys.size() > 0 && !PyABCUtil.isSubclass(type.getPyClass(), PyNames.MAPPING)) {
if (myUsedMappingKeys.size() > 0 && !PyABCUtil.isSubclass(type.getPyClass(), PyNames.MAPPING, null)) {
registerProblem(rightExpression, PyBundle.message("INSP.format.requires.mapping"));
return;
}
@@ -66,7 +66,7 @@ public class AddCallSuperQuickFix implements LocalQuickFix {
if (superClasses.length == 0) return;
final PyClass superClass = superClasses[0];
final PyFunction superInit = superClass.findMethodByName(PyNames.INIT, true);
final PyFunction superInit = superClass.findMethodByName(PyNames.INIT, true, null);
if (superInit == null) return;
final ParametersInfo origInfo = new ParametersInfo(problemFunction.getParameterList());
@@ -146,13 +146,13 @@ public class AddFieldQuickFix implements LocalQuickFix {
@Nullable
public static PsiElement addFieldToInit(Project project, PyClass cls, String itemName, Function<String, PyStatement> callback) {
if (cls != null && itemName != null) {
PyFunction init = cls.findMethodByName(PyNames.INIT, false);
PyFunction init = cls.findMethodByName(PyNames.INIT, false, null);
if (init != null) {
return appendToMethod(init, callback);
}
else { // no init! boldly copy ancestor's.
for (PyClass ancestor : cls.getAncestorClasses(null)) {
init = ancestor.findMethodByName(PyNames.INIT, false);
init = ancestor.findMethodByName(PyNames.INIT, false, null);
if (init != null) break;
}
PyFunction newInit = createInitMethod(project, cls, init);
@@ -61,7 +61,7 @@ public class PyChangeSignatureQuickFix implements LocalQuickFix {
final String complementaryName = PyNames.NEW.equals(functionName) ? PyNames.INIT : PyNames.NEW;
final TypeEvalContext context = TypeEvalContext.userInitiated(project, descriptor.getEndElement().getContainingFile());
final PyFunction complementaryMethod = myOverridenMethod ? (PyFunction)PySuperMethodsSearch.search(function, context).findFirst()
: cls.findMethodByName(complementaryName, true);
: cls.findMethodByName(complementaryName, true, null);
assert complementaryMethod != null;
final PyMethodDescriptor methodDescriptor = new PyMethodDescriptor(function) {
@@ -942,7 +942,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
// if we're in a class context and the class defines a variable with the same name, offer auto-import only as quickfix,
// not as popup
PyClass containingClass = PsiTreeUtil.getParentOfType(node, PyClass.class);
if (containingClass != null && (containingClass.findMethodByName(importFix.getNameToImport(), true) != null ||
if (containingClass != null && (containingClass.findMethodByName(importFix.getNameToImport(), true, null) != null ||
containingClass.findInstanceAttribute(importFix.getNameToImport(), true) != null)) {
return true;
}
@@ -116,7 +116,7 @@ public class SetupTaskIntrospector {
? PyClassNameIndex.findClass("distutils.command.build_ext.build_ext", file.getProject())
: file.findTopLevelClass(name);
if (taskClass != null) {
final PyTargetExpression description = taskClass.findClassAttribute("description", true);
final PyTargetExpression description = taskClass.findClassAttribute("description", true, null);
if (description != null) {
final String descriptionText = PyPsiUtils.strValue(PyPsiUtils.flattenParens(description.findAssignedValue()));
if (descriptionText != null) {
@@ -133,7 +133,7 @@ public class SetupTaskIntrospector {
}
}
final PyTargetExpression negativeOpt = taskClass.findClassAttribute("negative_opt", true);
final PyTargetExpression negativeOpt = taskClass.findClassAttribute("negative_opt", true, null);
final Map<String, String> negativeOptMap = negativeOpt == null
? Collections.<String, String>emptyMap()
: parseNegativeOpt(negativeOpt.findAssignedValue());
@@ -152,7 +152,7 @@ public class SetupTaskIntrospector {
private static List<PyExpression> resolveSequenceValue(PyClass aClass, String name) {
List<PyExpression> result = new ArrayList<PyExpression>();
collectSequenceElements(aClass.findClassAttribute(name, true), result);
collectSequenceElements(aClass.findClassAttribute(name, true, null), result);
return result;
}
@@ -689,7 +689,7 @@ public class PyUtil {
*/
@Nullable
public static PyFunction getInitMethod(@NotNull final PyClass pyClass) {
return pyClass.findMethodByName(PyNames.INIT, false);
return pyClass.findMethodByName(PyNames.INIT, false, null);
}
/**
@@ -551,7 +551,7 @@ public class PyCallExpressionHelper {
return Ref.create(t);
}
if (cls != null && t == null) {
final PyFunction newMethod = cls.findMethodByName(PyNames.NEW, true);
final PyFunction newMethod = cls.findMethodByName(PyNames.NEW, true, null);
if (newMethod != null && !PyBuiltinCache.getInstance(call).isBuiltin(newMethod)) {
return Ref.create(PyUnionType.createWeakType(new PyClassTypeImpl(cls, false)));
}
@@ -40,6 +40,7 @@ import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.documentation.docstrings.DocStringUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.stubs.PyClassElementType;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.PyResolveUtil;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
@@ -334,6 +335,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
return PyFileImpl.getStringListFromTargetExpression(PyNames.SLOTS, getClassAttributes());
}
@NotNull
public PyClass[] getSuperClasses(@Nullable TypeEvalContext context) {
if (context == null) {
@@ -530,10 +532,11 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
}
public PyFunction findMethodByName(@Nullable final String name, boolean inherited) {
@Override
public PyFunction findMethodByName(@Nullable final String name, boolean inherited, @Nullable TypeEvalContext context) {
if (name == null) return null;
NameFinder<PyFunction> proc = new NameFinder<PyFunction>(name);
visitMethods(proc, inherited, null);
visitMethods(proc, inherited, context);
return proc.getResult();
}
@@ -657,7 +660,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
if (value == null || PyNames.NONE.equals(value)) {
return NONE;
}
PyFunction method = findMethodByName(value, true);
PyFunction method = findMethodByName(value, true, null);
if (method != null) return new Maybe<PyCallable>(method);
}
return UNKNOWN_CALL;
@@ -694,7 +697,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
if (property != null) {
return property;
}
if (findMethodByName(name, false) != null || findClassAttribute(name, false) != null) {
if (findMethodByName(name, false, null) != null || findClassAttribute(name, false, null) != null) {
return null;
}
if (inherited) {
@@ -767,7 +770,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
return local;
}
if (inherited) {
if (name != null && (findMethodByName(name, false) != null || findClassAttribute(name, false) != null)) {
if (name != null && (findMethodByName(name, false, null) != null || findClassAttribute(name, false, null) != null)) {
return null;
}
for (PyClass cls : getAncestorClasses(null)) {
@@ -980,9 +983,9 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
@Override
public PyTargetExpression findClassAttribute(@NotNull String name, boolean inherited) {
public PyTargetExpression findClassAttribute(@NotNull String name, boolean inherited, TypeEvalContext context) {
final NameFinder<PyTargetExpression> processor = new NameFinder<PyTargetExpression>(name);
visitClassAttributes(processor, inherited, null);
visitClassAttributes(processor, inherited, context);
return processor.getResult();
}
@@ -1017,7 +1020,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
Map<String, PyTargetExpression> result = new HashMap<String, PyTargetExpression>();
collectAttributesInNew(result);
PyFunctionImpl initMethod = (PyFunctionImpl)findMethodByName(PyNames.INIT, false);
PyFunctionImpl initMethod = (PyFunctionImpl)findMethodByName(PyNames.INIT, false, null);
if (initMethod != null) {
collectInstanceAttributes(initMethod, result);
}
@@ -1034,7 +1037,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
private void collectAttributesInNew(@NotNull final Map<String, PyTargetExpression> result) {
final PyFunction newMethod = findMethodByName(PyNames.NEW, false);
final PyFunction newMethod = findMethodByName(PyNames.NEW, false, null);
if (newMethod != null) {
for (PyTargetExpression target : getTargetExpressions(newMethod)) {
result.put(target.getName(), target);
@@ -1131,7 +1134,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
}
}
if (pyClass.findClassAttribute(PyNames.DUNDER_METACLASS, false) != null) {
if (pyClass.findClassAttribute(PyNames.DUNDER_METACLASS, false, null) != null) {
return true;
}
return false;
@@ -1244,42 +1247,15 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
final PyClassStub stub = getStub();
final List<PyClassLikeType> result = new ArrayList<PyClassLikeType>();
// In some cases stub may not provide all information, so we use stubs only if AST access id disabled
if (!context.maySwitchToAST(this) && stub != null) {
final PsiFile file = getContainingFile();
if (file instanceof PyFile) {
for (QualifiedName name : stub.getSuperClasses()) {
result.add(name != null ? classTypeFromQName(name, (PyFile)file, context) : null);
}
}
if (!context.maySwitchToAST(this)) {
fillSuperClassesNoSwitchToAst(context, stub, result);
}
else {
for (PyExpression expression : getSuperClassExpressions()) {
context.getType(expression);
expression = unfoldClass(expression);
if (expression instanceof PyKeywordArgument) {
continue;
}
final PyType type = context.getType(expression);
PyClassLikeType classLikeType = null;
if (type instanceof PyClassLikeType) {
classLikeType = (PyClassLikeType)type;
}
else {
final PsiReference ref = expression.getReference();
if (ref != null) {
final PsiElement resolved = ref.resolve();
if (resolved instanceof PyClass) {
final PyType resolvedType = context.getType((PyClass)resolved);
if (resolvedType instanceof PyClassLikeType) {
classLikeType = (PyClassLikeType)resolvedType;
}
}
}
}
result.add(classLikeType);
}
fillSuperClassesSwitchingToAst(context, result);
}
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(this);
if (result.isEmpty() && isValid() && !builtinCache.isBuiltin(this)) {
final String implicitSuperName = LanguageLevel.forElement(this).isPy3K() ? PyNames.OBJECT : PyNames.FAKE_OLD_BASE;
@@ -1294,6 +1270,54 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
return result;
}
private void fillSuperClassesSwitchingToAst(@NotNull TypeEvalContext context, List<PyClassLikeType> result) {
for (PyExpression expression : getSuperClassExpressions()) {
context.getType(expression);
expression = unfoldClass(expression);
if (expression instanceof PyKeywordArgument) {
continue;
}
final PyType type = context.getType(expression);
PyClassLikeType classLikeType = null;
if (type instanceof PyClassLikeType) {
classLikeType = (PyClassLikeType)type;
}
else {
final PsiReference ref = expression.getReference();
if (ref != null) {
final PsiElement resolved = ref.resolve();
if (resolved instanceof PyClass) {
final PyType resolvedType = context.getType((PyClass)resolved);
if (resolvedType instanceof PyClassLikeType) {
classLikeType = (PyClassLikeType)resolvedType;
}
}
}
}
result.add(classLikeType);
}
}
private void fillSuperClassesNoSwitchToAst(@NotNull final TypeEvalContext context,
@Nullable final PyClassStub stub,
@NotNull final List<PyClassLikeType> result) {
final List<QualifiedName> qualifiedNames;
if (stub != null) {
qualifiedNames = Arrays.asList(stub.getSuperClasses());
}
else {
qualifiedNames = PyClassElementType.getSuperClassQNames(this);
}
final PsiFile file = getContainingFile();
if (file instanceof PyFile) {
for (QualifiedName name : qualifiedNames) {
result.add(name != null ? classTypeFromQName(name, (PyFile)file, context) : null);
}
}
}
@NotNull
@Override
public List<PyClassLikeType> getAncestorTypes(@NotNull TypeEvalContext context) {
@@ -1353,7 +1377,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
}
else {
final PyTargetExpression attribute = findClassAttribute(PyNames.DUNDER_METACLASS, false);
final PyTargetExpression attribute = findClassAttribute(PyNames.DUNDER_METACLASS, false, null);
if (attribute != null) {
return attribute.findAssignedValue();
}
@@ -1397,7 +1421,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
if (cls == metaClass) {
return false;
}
final PyFunction mroMethod = metaClass.findMethodByName(PyNames.MRO, true);
final PyFunction mroMethod = metaClass.findMethodByName(PyNames.MRO, true, null);
if (mroMethod != null) {
final PyClass mroClass = mroMethod.getContainingClass();
if (mroClass != null && mroClass != typeClass) {
@@ -81,7 +81,7 @@ public class PySubscriptionExpressionImpl extends PyElementImpl implements PySub
if (indexExpression != null) {
final PyType type = context.getType(getOperand());
final PyClass cls = (type instanceof PyClassType) ? ((PyClassType)type).getPyClass() : null;
if (cls != null && PyABCUtil.isSubclass(cls, PyNames.MAPPING)) {
if (cls != null && PyABCUtil.isSubclass(cls, PyNames.MAPPING, context)) {
return res;
}
if (type instanceof PySubscriptableType) {
@@ -247,7 +247,7 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl<PyTargetExpression
final PyType exprType = context.getType(expression);
if (exprType instanceof PyClassType) {
final PyClass cls = ((PyClassType)exprType).getPyClass();
final PyFunction enter = cls.findMethodByName(PyNames.ENTER, true);
final PyFunction enter = cls.findMethodByName(PyNames.ENTER, true, null);
if (enter != null) {
final PyType enterType = enter.getCallType(expression, Collections.<PyExpression, PyNamedParameter>emptyMap(), context);
if (enterType != null) {
@@ -52,7 +52,7 @@ public class KeywordArgumentCompletionUtil {
addKeywordArgumentVariants((PyCallable)def, callExpr, ret);
}
else if (def instanceof PyClass) {
PyFunction init = ((PyClass)def).findMethodByName(PyNames.INIT, true); // search in superclasses
PyFunction init = ((PyClass)def).findMethodByName(PyNames.INIT, true, null); // search in superclasses
if (init != null) {
addKeywordArgumentVariants(init, callExpr, ret);
}
@@ -136,14 +136,14 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
final PsiElement elt = rrr.getElement();
if (elt instanceof PyClass) {
PyClass cls = (PyClass)elt;
PyFunction init = cls.findMethodByName(PyNames.INIT, false);
PyFunction init = cls.findMethodByName(PyNames.INIT, false, null);
if (init != null) {
// replace
it.set(rrr.replace(init));
}
else { // init not found; maybe it's ancestor's
for (PyClass ancestor : cls.getAncestorClasses(myContext.getTypeEvalContext())) {
init = ancestor.findMethodByName(PyNames.INIT, false);
init = ancestor.findMethodByName(PyNames.INIT, false, null);
if (init != null) {
// add to results as low priority
it.add(new RatedResolveResult(RatedResolveResult.RATE_LOW, init));
@@ -53,7 +53,19 @@ public class PyClassElementType extends PyStubElementType<PyClassStub, PyClass>
}
public PyClassStub createStub(@NotNull final PyClass psi, final StubElement parentStub) {
final PyExpression[] exprs = psi.getSuperClassExpressions();
final List<QualifiedName> superClasses = getSuperClassQNames(psi);
final PyStringLiteralExpression docStringExpression = psi.getDocStringExpression();
return new PyClassStubImpl(psi.getName(), parentStub,
superClasses.toArray(new QualifiedName[superClasses.size()]),
PyPsiUtils.asQualifiedName(psi.getMetaClassExpression()),
psi.getOwnSlots(),
PyPsiUtils.strValue(docStringExpression),
getStubElementType());
}
@NotNull
public static List<QualifiedName> getSuperClassQNames(@NotNull final PyClass pyClass) {
final PyExpression[] exprs = pyClass.getSuperClassExpressions();
List<QualifiedName> superClasses = new ArrayList<QualifiedName>();
for (PyExpression expression : exprs) {
if (expression instanceof PyKeywordArgument) {
@@ -62,13 +74,7 @@ public class PyClassElementType extends PyStubElementType<PyClassStub, PyClass>
expression = PyClassImpl.unfoldClass(expression);
superClasses.add(PyPsiUtils.asQualifiedName(expression));
}
final PyStringLiteralExpression docStringExpression = psi.getDocStringExpression();
return new PyClassStubImpl(psi.getName(), parentStub,
superClasses.toArray(new QualifiedName[superClasses.size()]),
PyPsiUtils.asQualifiedName(psi.getMetaClassExpression()),
psi.getOwnSlots(),
PyPsiUtils.strValue(docStringExpression),
getStubElementType());
return superClasses;
}
public void serialize(@NotNull final PyClassStub pyClassStub, @NotNull final StubOutputStream dataStream) throws IOException {
@@ -106,7 +112,7 @@ public class PyClassElementType extends PyStubElementType<PyClassStub, PyClass>
sink.occurrence(PyClassNameIndexInsensitive.KEY, name.toLowerCase());
}
final PyClass pyClass = createPsi(stub);
for (String attribute: PyClassAttributesIndex.getAllDeclaredAttributeNames(pyClass)) {
for (String attribute : PyClassAttributesIndex.getAllDeclaredAttributeNames(pyClass)) {
sink.occurrence(PyClassAttributesIndex.KEY, attribute);
}
for (QualifiedName s : stub.getSuperClasses()) {
@@ -34,7 +34,7 @@ public class PyOverridingMethodsSearchExecutor implements QueryExecutor<PyFuncti
final AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
PyFunction overridingMethod;
try {
overridingMethod = pyClass.findMethodByName(baseMethod.getName(), false);
overridingMethod = pyClass.findMethodByName(baseMethod.getName(), false, null);
if (overridingMethod != null) {
final Property baseProperty = baseMethod.getProperty();
final Property overridingProperty = overridingMethod.getProperty();
@@ -52,7 +52,7 @@ public class PySuperMethodsSearchExecutor implements QueryExecutor<PsiElement, P
continue;
}
}
PyFunction superMethod = superClass.findMethodByName(name, false);
PyFunction superMethod = superClass.findMethodByName(name, false, null);
if (superMethod != null) {
final Property property = func.getProperty();
final Property superProperty = superMethod.getProperty();
@@ -18,6 +18,7 @@ package com.jetbrains.python.psi.types;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.PyClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author vlan
@@ -29,36 +30,36 @@ public class PyABCUtil {
public static boolean isSubclass(@NotNull PyClass subClass, @NotNull PyClass superClass) {
final String superName = superClass.getName();
if (superName != null) {
return isSubclass(subClass, superName, true);
return isSubclass(subClass, superName, true, null);
}
return false;
}
public static boolean isSubclass(@NotNull PyClass subClass, @NotNull String superClassName) {
return isSubclass(subClass, superClassName, true);
public static boolean isSubclass(@NotNull PyClass subClass, @NotNull String superClassName, @Nullable TypeEvalContext context) {
return isSubclass(subClass, superClassName, true, context);
}
public static boolean isSubclass(@NotNull PyClass subClass, @NotNull String superClassName, boolean inherited) {
public static boolean isSubclass(@NotNull PyClass subClass, @NotNull String superClassName, boolean inherited, @Nullable TypeEvalContext context) {
if (PyNames.CALLABLE.equals(superClassName)) {
return hasMethod(subClass, PyNames.CALL, inherited);
return hasMethod(subClass, PyNames.CALL, inherited, context);
}
if (PyNames.HASHABLE.equals(superClassName)) {
return hasMethod(subClass, PyNames.HASH, inherited);
return hasMethod(subClass, PyNames.HASH, inherited, context);
}
final boolean hasIter = hasMethod(subClass, PyNames.ITER, inherited);
final boolean hasGetItem = hasMethod(subClass, PyNames.GETITEM, inherited);
final boolean hasIter = hasMethod(subClass, PyNames.ITER, inherited, context);
final boolean hasGetItem = hasMethod(subClass, PyNames.GETITEM, inherited, context);
if (PyNames.ITERABLE.equals(superClassName)) {
return hasIter || hasGetItem;
}
if (PyNames.ITERATOR.equals(superClassName)) {
return (hasIter && (hasMethod(subClass, PyNames.NEXT, inherited) || hasMethod(subClass,
PyNames.DUNDER_NEXT, inherited))) || hasGetItem;
return (hasIter && (hasMethod(subClass, PyNames.NEXT, inherited, context) || hasMethod(subClass,
PyNames.DUNDER_NEXT, inherited, context))) || hasGetItem;
}
final boolean isSized = hasMethod(subClass, PyNames.LEN, inherited);
final boolean isSized = hasMethod(subClass, PyNames.LEN, inherited, context);
if (PyNames.SIZED.equals(superClassName)) {
return isSized;
}
final boolean isContainer = hasMethod(subClass, PyNames.CONTAINS, inherited);
final boolean isContainer = hasMethod(subClass, PyNames.CONTAINS, inherited, context);
if (PyNames.CONTAINER.equals(superClassName)) {
return isContainer;
}
@@ -66,16 +67,16 @@ public class PyABCUtil {
return isSized && hasIter && isContainer && hasGetItem;
}
if (PyNames.MAPPING.equals(superClassName)) {
return isSized && hasIter && isContainer && hasGetItem && hasMethod(subClass, PyNames.KEYS, inherited);
return isSized && hasIter && isContainer && hasGetItem && hasMethod(subClass, PyNames.KEYS, inherited, context);
}
if (PyNames.ABC_COMPLEX.equals(superClassName)) {
return hasMethod(subClass, "__complex__", inherited);
return hasMethod(subClass, "__complex__", inherited, context);
}
if (PyNames.ABC_REAL.equals(superClassName)) {
return hasMethod(subClass, "__float__", inherited);
return hasMethod(subClass, "__float__", inherited, context);
}
if (PyNames.ABC_INTEGRAL.equals(superClassName)) {
return hasMethod(subClass, "__int__", inherited);
return hasMethod(subClass, "__int__", inherited, context);
}
if (PyNames.ABC_NUMBER.equals(superClassName) && "Decimal".equals(subClass.getName())) {
return true;
@@ -95,11 +96,11 @@ public class PyABCUtil {
final PyClassLikeType metaClassType = classType.getMetaClassType(context, true);
if (metaClassType instanceof PyClassType) {
final PyClassType metaClass = (PyClassType)metaClassType;
return isSubclass(metaClass.getPyClass(), superClassName, true);
return isSubclass(metaClass.getPyClass(), superClassName, true, null);
}
}
else {
return isSubclass(pyClass, superClassName, true);
return isSubclass(pyClass, superClassName, true, null);
}
}
if (type instanceof PyUnionType) {
@@ -116,7 +117,7 @@ public class PyABCUtil {
return false;
}
private static boolean hasMethod(PyClass cls, String name, boolean inherited) {
return cls.findMethodByName(name, inherited) != null || cls.findClassAttribute(name, inherited) != null;
private static boolean hasMethod(PyClass cls, String name, boolean inherited, TypeEvalContext context) {
return cls.findMethodByName(name, inherited, context) != null || cls.findClassAttribute(name, inherited, context) != null;
}
}
@@ -312,7 +312,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
return true;
}
final PyClass cls = getPyClass();
if (PyABCUtil.isSubclass(cls, PyNames.CALLABLE)) {
if (PyABCUtil.isSubclass(cls, PyNames.CALLABLE, null)) {
return true;
}
return false;
@@ -77,7 +77,7 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
if (info instanceof PyChangeInfo && info.isNameChanged()) {
final PyFunction function = ((PyChangeInfo)info).getMethod();
final PyClass clazz = function.getContainingClass();
if (clazz != null && clazz.findMethodByName(info.getNewName(), true) != null) {
if (clazz != null && clazz.findMethodByName(info.getNewName(), true, null) != null) {
conflicts.putValue(function, RefactoringBundle.message("method.0.is.already.defined.in.the.1",
info.getNewName(),
"class " + clazz.getQualifiedName()));
@@ -157,7 +157,7 @@ public final class PyClassRefactoringUtil {
for (final PyFunction method : methods) {
final PyFunction existingMethod = destination.findMethodByName(method.getName(), false);
final PyFunction existingMethod = destination.findMethodByName(method.getName(), false, null);
if ((existingMethod != null) && skipIfExist) {
result.add(existingMethod);
continue; //We skip adding if class already has this method.
@@ -589,7 +589,7 @@ public final class PyClassRefactoringUtil {
@NotNull final PyClass aClass,
@NotNull final String attributeName,
@NotNull final String value) {
if (aClass.findClassAttribute(attributeName, false) != null) {
if (aClass.findClassAttribute(attributeName, false, null) != null) {
return null; //Do not add any if exist already
}
final PyElementGenerator generator = PyElementGenerator.getInstance(aClass.getProject());
@@ -70,7 +70,7 @@ class ClassFieldsManager extends FieldsManager {
@Override
protected boolean classHasField(@NotNull final PyClass pyClass, @NotNull final String fieldName) {
return pyClass.findClassAttribute(fieldName, true) != null;
return pyClass.findClassAttribute(fieldName, true, null) != null;
}
@NotNull
@@ -223,7 +223,7 @@ class MethodsManager extends MembersManager<PyFunction> {
final PyClass clazz = PyUtil.getContainingClassOrSelf(pyFunction);
assert clazz != null : "Refactoring called on function, not method: " + pyFunction;
for (final PyClass parentClass : clazz.getSuperClasses(null)) {
final PyFunction parentMethod = parentClass.findMethodByName(pyFunction.getName(), true);
final PyFunction parentMethod = parentClass.findMethodByName(pyFunction.getName(), true, null);
if (parentMethod != null) {
return true;
}
@@ -687,7 +687,7 @@ public class PyExtractMethodUtil {
ScopeOwner owner = parent;
while (owner != null) {
if (owner instanceof PyClass) {
if (((PyClass)owner).findMethodByName(s, true) != null) {
if (((PyClass)owner).findMethodByName(s, true, null) != null) {
return false;
}
}
@@ -173,7 +173,7 @@ public class PyIntroduceFieldHandler extends IntroduceHandler {
PyClass clazz = PyUtil.getContainingClassOrSelf(expr);
PsiElement current = PyUtil.getConcealingParent(expression);
if (clazz != null && current != null && current instanceof PyFunction) {
PyFunction init = clazz.findMethodByName(PyNames.INIT, false);
PyFunction init = clazz.findMethodByName(PyNames.INIT, false, null);
if (current == init) {
return true;
}
@@ -183,7 +183,7 @@ public class PyIntroduceFieldHandler extends IntroduceHandler {
@Nullable
private static PsiElement addFieldToSetUp(PyClass clazz, final Function<String, PyStatement> callback) {
final PyFunction init = clazz.findMethodByName(PythonUnitTestUtil.TESTCASE_SETUP_NAME, false);
final PyFunction init = clazz.findMethodByName(PythonUnitTestUtil.TESTCASE_SETUP_NAME, false, null);
if (init != null) {
return AddFieldQuickFix.appendToMethod(init, callback);
}
@@ -64,7 +64,7 @@ public class RenamePyClassProcessor extends RenamePyElementProcessor {
@Override
public Collection<PsiReference> findReferences(final PsiElement element) {
if (element instanceof PyClass) {
final PyFunction initMethod = ((PyClass)element).findMethodByName(PyNames.INIT, true);
final PyFunction initMethod = ((PyClass)element).findMethodByName(PyNames.INIT, true, null);
if (initMethod != null) {
final List<PsiReference> allRefs = Collections.synchronizedList(new ArrayList<PsiReference>());
allRefs.addAll(super.findReferences(element));
@@ -50,11 +50,11 @@ public abstract class RenamePyElementProcessor extends RenamePsiElementProcessor
if (conflictingClass != null) {
conflicts.putValue(conflictingClass, "A class named '" + newName + "' is already defined in class '" + pyClass.getName() + "'");
}
PyFunction conflictingFunction = pyClass.findMethodByName(newName, true);
PyFunction conflictingFunction = pyClass.findMethodByName(newName, true, null);
if (conflictingFunction != null) {
conflicts.putValue(conflictingFunction, "A function named '" + newName + "' is already defined in class '" + pyClass.getName() + "'");
}
PyTargetExpression conflictingAttribute = pyClass.findClassAttribute(newName, true);
PyTargetExpression conflictingAttribute = pyClass.findClassAttribute(newName, true, null);
if (conflictingAttribute != null) {
conflicts.putValue(conflictingAttribute, "An attribute named '" + newName + "' is already defined in class '" + pyClass.getName() + "'");
}
@@ -204,7 +204,7 @@ public class PythonUnitTestUtil {
locations.add(new PsiLocation<PyClass>(project, cls));
}
else {
final PyFunction method = cls.findMethodByName(methodName, true);
final PyFunction method = cls.findMethodByName(methodName, true, null);
if (method == null) {
continue;
}
@@ -132,10 +132,10 @@ public class PyClassicPropertyTest extends PyTestCase {
*/
public void testGetProperty() {
final PyFunction getter = myClass.findMethodByName("v5getter", false);
final PyFunction getter = myClass.findMethodByName("v5getter", false, null);
assertNotNull(getter.getProperty());
final PyFunction setter = myClass.findMethodByName("v5setter", false);
final PyFunction setter = myClass.findMethodByName("v5setter", false, null);
assertNotNull(setter.getProperty());
}
@@ -111,7 +111,7 @@ public class PyOverrideTest extends PyTestCase {
myFixture.configureByFile("override/" + getTestName(true) + ".py");
PyClass dateClass = PyClassNameIndex.findClass("datetime.date", myFixture.getProject());
assertNotNull(dateClass);
PyFunction initMethod = dateClass.findMethodByName(PyNames.INIT, false);
PyFunction initMethod = dateClass.findMethodByName(PyNames.INIT, false, null);
assertNotNull(initMethod);
PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), getTopLevelClass(0),
Collections.singletonList(new PyMethodMember(initMethod)), false);
@@ -183,7 +183,7 @@ public class PyOverrideTest extends PyTestCase {
public void testInstanceCheck() {
myFixture.configureByFile("override/" + getTestName(true) + ".py");
final PyClass cls = getTopLevelClass(0);
final PyFunction method = cls.findMethodByName("__instancecheck__", true);
final PyFunction method = cls.findMethodByName("__instancecheck__", true, null);
PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), cls, Collections.singletonList(new PyMethodMember(method)), false);
myFixture.checkResultByFile("override/" + getTestName(true) + "_after.py", true);
}
@@ -399,7 +399,7 @@ public class PyStubsTest extends PyTestCase {
final PyFile file = getTestFile();
final PyClass c = file.findTopLevelClass("C");
assertNotNull(c);
final PyTargetExpression foo = c.findClassAttribute("foo", false);
final PyTargetExpression foo = c.findClassAttribute("foo", false, null);
final String docString = foo.getDocStringValue();
assertEquals("Foo docstring.", docString);
}
@@ -95,7 +95,7 @@ public class PyClassMROTest extends PyTestCase {
}
public void assertMRO(@NotNull PyClass cls, @NotNull String... mro) {
final List<PyClassLikeType> types = cls.getAncestorTypes(TypeEvalContext.codeInsightFallback(cls.getProject()));
final List<PyClassLikeType> types = cls.getAncestorTypes(TypeEvalContext.deepCodeInsight(cls.getProject()));
final List<String> classNames = new ArrayList<String>();
for (PyClassLikeType type : types) {
if (type != null) {
@@ -87,7 +87,7 @@ public abstract class PyClassRefactoringTest extends PyTestCase {
private PyElement findField(final String className, final String memberName) {
final PyClass aClass = findClass(className);
final PyTargetExpression attribute = aClass.findClassAttribute(memberName, false);
final PyTargetExpression attribute = aClass.findClassAttribute(memberName, false, null);
if (attribute != null) {
return attribute;
}
@@ -96,7 +96,7 @@ public abstract class PyClassRefactoringTest extends PyTestCase {
private PyFunction findMethod(final String className, final String name) {
final PyClass clazz = findClass(className);
return clazz.findMethodByName(name, false);
return clazz.findMethodByName(name, false, null);
}
protected PyClass findClass(final String name) {