public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { if (!TypeEvalStack.mayEvaluate(this)) { return null; } try { final boolean qualified = isQualified(); if (!qualified) { String name = getReferencedName(); if (PyNames.NONE.equals(name)) { return PyNoneType.INSTANCE; } } PyType type = getTypeFromProviders(context); if (type != null) { return type; } if (qualified) { PyType maybe_type = PyUtil.getSpecialAttributeType(this, context); if (maybe_type != null) return maybe_type; Ref<PyType> typeOfProperty = getTypeOfProperty(context); if (typeOfProperty != null) { return typeOfProperty.get(); } } final PsiPolyVariantReference reference = getReference(PyResolveContext.noImplicits().withTypeEvalContext(context)); final List<PsiElement> targets = PyUtil.multiResolveTopPriority(reference); if (targets.isEmpty()) { return getQualifiedReferenceTypeByControlFlow(context); } final List<PyType> members = new ArrayList<PyType>(); for (PsiElement target : targets) { if (target == this || target == null) { continue; } if (!target.isValid()) { LOG.error( "Reference " + this + " resolved to invalid element " + target + " (text=" + target.getText() + ")"); continue; } members.add(getTypeFromTarget(target, context, this)); } return PyUnionType.union(members); } finally { TypeEvalStack.evaluated(this); } }
@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; }
private static PyType getTypeByControlFlow( @NotNull String name, @NotNull TypeEvalContext context, @NotNull PyExpression anchor, @NotNull ScopeOwner scopeOwner) { PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class); try { final PyElement element = augAssignment != null ? augAssignment : anchor; final List<ReadWriteInstruction> defs = PyDefUseUtil.getLatestDefs(scopeOwner, name, element, true); if (!defs.isEmpty()) { PyType type = defs.get(0).getType(context, anchor); for (int i = 1; i < defs.size(); i++) { type = PyUnionType.union(type, defs.get(i).getType(context, anchor)); } return type; } } catch (PyDefUseUtil.InstructionNotFoundException ignored) { } return null; }