@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])); } }
@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()); } } }