@Override public void visitPyReferenceExpression(PyReferenceExpression node) { final PyExpression qualifier = node.getQualifier(); if (qualifier == null || PyNames.CANONICAL_SELF.equals(qualifier.getText())) return; if (myTypeEvalContext.getType(qualifier) instanceof PyNamedTupleType) return; final String name = node.getName(); final List<LocalQuickFix> quickFixes = new ArrayList<LocalQuickFix>(); quickFixes.add(new PyRenameElementQuickFix()); if (name != null && name.startsWith("_") && !name.startsWith("__") && !name.endsWith("__")) { final PsiReference reference = node.getReference(getResolveContext()); if (reference == null) return; final PsiElement resolvedExpression = reference.resolve(); final PyClass resolvedClass = getClassOwner(resolvedExpression); if (resolvedExpression instanceof PyTargetExpression) { final String newName = StringUtil.trimLeading(name, '_'); if (resolvedClass != null) { final String qFixName = resolvedClass.getProperties().containsKey(newName) ? PyBundle.message("QFIX.use.property") : PyBundle.message("QFIX.add.property"); quickFixes.add(new PyAddPropertyForFieldQuickFix(qFixName)); final Collection<String> usedNames = PyRefactoringUtil.collectUsedNames(resolvedClass); if (!usedNames.contains(newName)) { quickFixes.add(new PyMakePublicQuickFix()); } } } final PyClass parentClass = getClassOwner(node); if (parentClass != null) { if (PyTestUtil.isPyTestClass(parentClass) && ignoreTestFunctions) return; if (parentClass.isSubclass(resolvedClass)) return; PyClass outerClass = getClassOwner(parentClass); while (outerClass != null) { if (outerClass.isSubclass(resolvedClass)) return; outerClass = getClassOwner(outerClass); } } final PyType type = myTypeEvalContext.getType(qualifier); final String bundleKey = type instanceof PyModuleType ? "INSP.protected.member.$0.access.module" : "INSP.protected.member.$0.access"; registerProblem( node, PyBundle.message(bundleKey, name), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, null, quickFixes.toArray(new LocalQuickFix[quickFixes.size() - 1])); } }
@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; }
@Override public void visitPyReferenceExpression(PyReferenceExpression node) { super.visitPyReferenceExpression(node); final PsiElement result = node.getReference().resolve(); if (result != null && PsiTreeUtil.getParentOfType(result, ScopeOwner.class) == myScope) { if (result instanceof PyParameter && myScope instanceof PyFunction) { final PyFunction function = (PyFunction) myScope; final PyParameter[] parameters = function.getParameterList().getParameters(); if (parameters.length > 0 && result == parameters[0]) { final PyFunction.Modifier modifier = function.getModifier(); if (modifier != PyFunction.Modifier.STATICMETHOD) { // 'self' is not a local scope dependency return; } } } hasLocalScopeDependencies = true; } }
@NotNull private static List<PsiElement> tryResolving( @NotNull PyExpression expression, @NotNull TypeEvalContext context) { final List<PsiElement> elements = Lists.newArrayList(); if (expression instanceof PyReferenceExpression) { final PyReferenceExpression referenceExpr = (PyReferenceExpression) expression; final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); final PsiPolyVariantReference reference = referenceExpr.getReference(resolveContext); final List<PsiElement> resolved = PyUtil.multiResolveTopPriority(reference); for (PsiElement element : resolved) { if (element instanceof PyFunction) { final PyFunction function = (PyFunction) element; if (PyUtil.isInit(function)) { final PyClass cls = function.getContainingClass(); if (cls != null) { elements.add(cls); continue; } } } else if (element instanceof PyTargetExpression) { final PyTargetExpression targetExpr = (PyTargetExpression) element; // XXX: Requires switching from stub to AST final PyExpression assignedValue = targetExpr.findAssignedValue(); if (assignedValue != null) { elements.add(assignedValue); continue; } } if (element != null) { elements.add(element); } } } return !elements.isEmpty() ? elements : Collections.singletonList(expression); }
@Override public void visitPyReferenceExpression(final PyReferenceExpression node) { if (node.getContainingFile() instanceof PyExpressionCodeFragment) { return; } // Ignore global statements arguments if (PyGlobalStatementNavigator.getByArgument(node) != null) { return; } // Ignore qualifier inspections if (node.getQualifier() != null) { return; } // Ignore import subelements if (PsiTreeUtil.getParentOfType(node, PyImportStatementBase.class) != null) { return; } final String name = node.getReferencedName(); if (name == null) { return; } final ScopeOwner owner = ScopeUtil.getDeclarationScopeOwner(node, name); final Set<ScopeOwner> largeFunctions = getSession().getUserData(LARGE_FUNCTIONS_KEY); assert largeFunctions != null; if (owner == null || largeFunctions.contains(owner)) { return; } // Ignore references declared in outer scopes if (owner != ScopeUtil.getScopeOwner(node)) { return; } final Scope scope = ControlFlowCache.getScope(owner); // Ignore globals and if scope even doesn't contain such a declaration if (scope.isGlobal(name) || (!scope.containsDeclaration(name))) { return; } // Start DFA from the assignment statement in case of augmented assignments final PsiElement anchor; final PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(node, PyAugAssignmentStatement.class); if (augAssignment != null && name.equals(augAssignment.getTarget().getName())) { anchor = augAssignment; } else { anchor = node; } final ScopeVariable variable; try { variable = scope.getDeclaredVariable(anchor, name); } catch (DFALimitExceededException e) { largeFunctions.add(owner); registerLargeFunction(owner); return; } if (variable == null) { if (!isFirstUnboundRead(node, owner)) { return; } final PsiPolyVariantReference ref = node.getReference(resolveWithoutImplicits()); if (ref == null) { return; } final PsiElement resolved = ref.resolve(); final boolean isBuiltin = PyBuiltinCache.getInstance(node).hasInBuiltins(resolved); if (owner instanceof PyClass) { if (isBuiltin || ScopeUtil.getDeclarationScopeOwner(owner, name) != null) { return; } } if (PyUnreachableCodeInspection.hasAnyInterruptedControlFlowPaths(node)) { return; } if (owner instanceof PyFile) { if (isBuiltin) { return; } if (resolved != null && !PyUtil.inSameFile(node, resolved)) { return; } registerProblem(node, PyBundle.message("INSP.unbound.name.not.defined", name)); } else { registerProblem( node, PyBundle.message("INSP.unbound.local.variable", node.getName()), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, null, new AddGlobalQuickFix()); } } }