@NotNull public QualifiedResolveResult followAssignmentsChain(PyResolveContext resolveContext) { PyReferenceExpression seeker = this; QualifiedResolveResult ret = null; List<PyExpression> qualifiers = new ArrayList<PyExpression>(); PyExpression qualifier = seeker.getQualifier(); if (qualifier != null) { qualifiers.add(qualifier); } Set<PsiElement> visited = new HashSet<PsiElement>(); visited.add(this); SEARCH: while (ret == null) { ResolveResult[] targets = seeker.getReference(resolveContext).multiResolve(false); for (ResolveResult target : targets) { PsiElement elt = target.getElement(); if (elt instanceof PyTargetExpression) { PsiElement assigned_from = null; final PyTargetExpression expr = (PyTargetExpression) elt; final TypeEvalContext context = resolveContext.getTypeEvalContext(); if (context.maySwitchToAST(expr) || expr.getStub() == null) { assigned_from = expr.findAssignedValue(); } // TODO: Maybe findAssignedValueByStub() should become a part of the PyTargetExpression // interface else if (elt instanceof PyTargetExpressionImpl) { assigned_from = ((PyTargetExpressionImpl) elt).findAssignedValueByStub(context); } if (assigned_from instanceof PyReferenceExpression) { if (visited.contains(assigned_from)) { break; } visited.add(assigned_from); seeker = (PyReferenceExpression) assigned_from; if (seeker.getQualifier() != null) { qualifiers.add(seeker.getQualifier()); } continue SEARCH; } else if (assigned_from != null) ret = new QualifiedResolveResultImpl(assigned_from, qualifiers, false); } else if (ret == null && elt instanceof PyElement && target.isValidResult()) { // remember this result, but a further reference may be the next resolve result ret = new QualifiedResolveResultImpl( elt, qualifiers, target instanceof ImplicitResolveResult); } } // all resolve results checked, reassignment not detected, nothing more to do break; } if (ret == null) ret = EMPTY_RESULT; return ret; }
@Nullable public Ref<PyType> getTypeOfProperty(@NotNull TypeEvalContext context) { final PyExpression qualifier = getQualifier(); final String name = getName(); if (name != null && qualifier != null) { final PyType qualifierType = context.getType(qualifier); return getTypeOfProperty(qualifierType, name, context); } return null; }
@Nullable public PyType getQualifiedReferenceTypeByControlFlow(@NotNull TypeEvalContext context) { PyExpression qualifier = getQualifier(); if (context.allowDataFlow(this) && qualifier != null) { PyExpression next = qualifier; while (next != null) { qualifier = next; next = qualifier instanceof PyQualifiedExpression ? ((PyQualifiedExpression) qualifier).getQualifier() : null; } final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(this); final QualifiedName qname = asQualifiedName(); if (qname != null && scopeOwner != null) { return getTypeByControlFlow(qname.toString(), context, qualifier, scopeOwner); } } return null; }
@Nullable public static PyType getTypeFromTarget( @NotNull final PsiElement target, final TypeEvalContext context, PyReferenceExpression anchor) { if (!(target instanceof PyTargetExpression)) { // PyTargetExpression will ask about its type itself final PyType pyType = getReferenceTypeFromProviders(target, context, anchor); if (pyType != null) { return pyType; } } if (target instanceof PyTargetExpression) { final String name = ((PyTargetExpression) target).getName(); if (PyNames.NONE.equals(name)) { return PyNoneType.INSTANCE; } if (PyNames.TRUE.equals(name) || PyNames.FALSE.equals(name)) { return PyBuiltinCache.getInstance(target).getBoolType(); } } if (target instanceof PyFile) { return new PyModuleType((PyFile) target); } if (target instanceof PyImportedModule) { return new PyImportedModuleType((PyImportedModule) target); } if ((target instanceof PyTargetExpression || target instanceof PyNamedParameter) && anchor != null && context.allowDataFlow(anchor)) { final ScopeOwner scopeOwner = PsiTreeUtil.getStubOrPsiParentOfType(anchor, ScopeOwner.class); if (scopeOwner != null && scopeOwner == PsiTreeUtil.getStubOrPsiParentOfType(target, ScopeOwner.class)) { final String name = ((PyElement) target).getName(); if (name != null) { final PyType type = getTypeByControlFlow(name, context, anchor, scopeOwner); if (type != null) { return type; } } } } if (target instanceof PyFunction) { final PyDecoratorList decoratorList = ((PyFunction) target).getDecoratorList(); if (decoratorList != null) { final PyDecorator propertyDecorator = decoratorList.findDecorator(PyNames.PROPERTY); if (propertyDecorator != null) { return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY); } for (PyDecorator decorator : decoratorList.getDecorators()) { final QualifiedName qName = decorator.getQualifiedName(); if (qName != null && (qName.endsWith(PyNames.SETTER) || qName.endsWith(PyNames.DELETER) || qName.endsWith(PyNames.GETTER))) { return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY); } } } } if (target instanceof PyTypedElement) { return context.getType((PyTypedElement) target); } if (target instanceof PsiDirectory) { final PsiDirectory dir = (PsiDirectory) target; PsiFile file = dir.findFile(PyNames.INIT_DOT_PY); if (file != null) { return getTypeFromTarget(file, context, anchor); } if (PyUtil.isPackage(dir, anchor)) { final PsiFile containingFile = anchor.getContainingFile(); if (containingFile instanceof PyFile) { final QualifiedName qualifiedName = QualifiedNameFinder.findShortestImportableQName(dir); if (qualifiedName != null) { final PyImportedModule module = new PyImportedModule(null, (PyFile) containingFile, qualifiedName); return new PyImportedModuleType(module); } } } } return null; }