private static boolean isFirstUnboundRead( @NotNull PyReferenceExpression node, @NotNull ScopeOwner owner) { final String nodeName = node.getReferencedName(); final Scope scope = ControlFlowCache.getScope(owner); final ControlFlow flow = ControlFlowCache.getControlFlow(owner); final Instruction[] instructions = flow.getInstructions(); final int num = ControlFlowUtil.findInstructionNumberByElement(instructions, node); if (num < 0) { return true; } final Ref<Boolean> first = Ref.create(true); ControlFlowUtil.iteratePrev( num, instructions, new Function<Instruction, ControlFlowUtil.Operation>() { @Override public ControlFlowUtil.Operation fun(Instruction instruction) { if (instruction instanceof ReadWriteInstruction) { final ReadWriteInstruction rwInstruction = (ReadWriteInstruction) instruction; final String name = rwInstruction.getName(); final PsiElement element = rwInstruction.getElement(); if (element != null && name != null && name.equals(nodeName) && instruction.num() != num) { try { if (scope.getDeclaredVariable(element, name) == null) { final ReadWriteInstruction.ACCESS access = rwInstruction.getAccess(); if (access.isReadAccess()) { first.set(false); return ControlFlowUtil.Operation.BREAK; } } } catch (DFALimitExceededException e) { first.set(false); } return ControlFlowUtil.Operation.CONTINUE; } } return ControlFlowUtil.Operation.NEXT; } }); return first.get(); }
private void processElement(@NotNull final PsiNameIdentifierOwner element) { if (isConditional(element)) { return; } final String name = element.getName(); final ScopeOwner owner = ScopeUtil.getScopeOwner(element); if (owner != null && name != null) { final Instruction[] instructions = ControlFlowCache.getControlFlow(owner).getInstructions(); PsiElement elementInControlFlow = element; if (element instanceof PyTargetExpression) { final PyImportStatement importStatement = PsiTreeUtil.getParentOfType(element, PyImportStatement.class); if (importStatement != null) { elementInControlFlow = importStatement; } } final int startInstruction = ControlFlowUtil.findInstructionNumberByElement(instructions, elementInControlFlow); if (startInstruction < 0) { return; } final Ref<PsiElement> readElementRef = Ref.create(null); final Ref<PsiElement> writeElementRef = Ref.create(null); ControlFlowUtil.iteratePrev( startInstruction, instructions, new Function<Instruction, ControlFlowUtil.Operation>() { @Override public ControlFlowUtil.Operation fun(Instruction instruction) { if (instruction instanceof ReadWriteInstruction && instruction.num() != startInstruction) { final ReadWriteInstruction rwInstruction = (ReadWriteInstruction) instruction; if (name.equals(rwInstruction.getName())) { final PsiElement originalElement = rwInstruction.getElement(); if (originalElement != null) { if (rwInstruction.getAccess().isReadAccess()) { readElementRef.set(originalElement); } if (rwInstruction.getAccess().isWriteAccess()) { if (originalElement != element) { writeElementRef.set(originalElement); } } } return ControlFlowUtil.Operation.CONTINUE; } } return ControlFlowUtil.Operation.NEXT; } }); final PsiElement writeElement = writeElementRef.get(); if (writeElement != null && readElementRef.get() == null) { final List<LocalQuickFix> quickFixes = new ArrayList<LocalQuickFix>(); if (suggestRename(element, writeElement)) { quickFixes.add(new PyRenameElementQuickFix()); } final PsiElement identifier = element.getNameIdentifier(); registerProblem( identifier != null ? identifier : element, PyBundle.message("INSP.redeclared.name", name), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, null, quickFixes.toArray(new LocalQuickFix[quickFixes.size()])); } } }