List<Info> (PsiElement body, Set<? super PsiVariable> outUsedVariables) { if (body == null) { return null; } ControlFlow flow; try { flow = ControlFlowFactory.getControlFlow(body, ourPolicy, ControlFlowOptions.create(true, false, false)); } catch (AnalysisCanceledException e) { return null; } List<Instruction> instructions = flow.getInstructions(); if (LOG.isDebugEnabled()) { LOG.debug(flow.toString()); } Set<PsiVariable> assignedVariables = new HashSet<>(); Set<PsiVariable> assignedSeveralTimes = new HashSet<>(); Set<PsiVariable> readVariables = new HashSet<>(); for (int i = 0; i < instructions.size(); i++) { Instruction instruction = instructions.get(i); ProgressManager.checkCanceled(); if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; PsiElement context = flow.getElement(i); context = PsiTreeUtil.getParentOfType(context, PsiStatement.class, false); PsiVariable psiVariable = writeInstruction.variable; if (context != null && !(context instanceof PsiDeclarationStatement && psiVariable.getInitializer() == null)) { if (!assignedVariables.add(psiVariable)) { assignedSeveralTimes.add(psiVariable); } } } else if (instruction instanceof ReadVariableInstruction) { ReadVariableInstruction readInstruction = (ReadVariableInstruction)instruction; readVariables.add(readInstruction.variable); } } Map<InstructionKey, InstructionState> stateMap; try { stateMap = InstructionStateWalker.getStates(instructions); } catch (InstructionKey.OverflowException e) { LOG.error("Failed to compute paths in the control flow graph", e, flow.toString()); return null; } InstructionState[] states = stateMap.values().toArray(new InstructionState[0]); Arrays.sort(states); BitSet usefulWrites = new BitSet(instructions.size()); Deque<InstructionState> queue = new ArrayDeque<>(8); for (int i = states.length - 1; i >= 0; i--) { final InstructionState outerState = states[i]; if (outerState.isVisited()) continue; outerState.touch(); for (PsiVariable psiVariable : assignedVariables) { if (psiVariable instanceof PsiField) { outerState.addUsed(psiVariable); } } queue.addLast(outerState); while (!queue.isEmpty()) { ProgressManager.checkCanceled(); InstructionState state = queue.removeFirst(); state.markVisited(); InstructionKey key = state.getInstructionKey(); if (key.getOffset() < instructions.size()) { Instruction instruction = instructions.get(key.getOffset()); if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; PsiVariable psiVariable = writeInstruction.variable; outUsedVariables.add(psiVariable); if (state.removeUsed(psiVariable)) { usefulWrites.set(key.getOffset()); } } else if (instruction instanceof ReadVariableInstruction) { ReadVariableInstruction readInstruction = (ReadVariableInstruction)instruction; state.addUsed(readInstruction.variable); outUsedVariables.add(readInstruction.variable); } else { state.touch(); } } List<InstructionKey> backwardTraces = state.getBackwardTraces(); for (InstructionKey prevKeys : backwardTraces) { InstructionState prevState = stateMap.get(prevKeys); if (prevState != null && !prevState.contains(state)) { prevState.addUsedFrom(state); queue.addLast(prevState); } } } } List<Info> unusedDefs = new ArrayList<>(); for (int i = 0; i < instructions.size(); i++) { Instruction instruction = instructions.get(i); if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; if (!usefulWrites.get(i)) { PsiElement context = PsiTreeUtil.getNonStrictParentOfType(flow.getElement(i), PsiStatement.class, PsiAssignmentExpression.class, PsiUnaryExpression.class); PsiVariable psiVariable = writeInstruction.variable; if (context != null) { if (context instanceof PsiDeclarationStatement && psiVariable.getInitializer() == null) { if (!assignedVariables.contains(psiVariable)) { unusedDefs.add(new Info(psiVariable, context, false, assignedSeveralTimes.contains(psiVariable))); } } else { unusedDefs.add(new Info(psiVariable, context, readVariables.contains(psiVariable), assignedSeveralTimes.contains(psiVariable))); } } } } } return unusedDefs; }