/** * Bottom-up approach, keeping track of which variables will be read by successor elements. */ private void verifyBlock(CfgBlock block, LiveVariables blockLiveVariables, Set<Symbol> readSymbols) { Set<Symbol> willBeRead = new HashSet<>(blockLiveVariables.getOut()); for (Tree element : Lists.reverse(block.elements())) { Map<Symbol, VariableUsage> usagesInElement = blockLiveVariables.getVariableUsages(element); for (Map.Entry<Symbol, VariableUsage> symbolWithUsage : usagesInElement.entrySet()) { Symbol symbol = symbolWithUsage.getKey(); if (!readSymbols.contains(symbol)) { // will be reported by S1481 continue; } VariableUsage usage = symbolWithUsage.getValue(); if (usage.isWrite() && !usage.isRead()) { if (!willBeRead.contains(symbol) && !shouldSkip(element, symbol)) { context().newIssue(this, element, String.format(MESSAGE_TEMPLATE, symbol.name())); } willBeRead.remove(symbol); } else if (usage.isRead()) { willBeRead.add(symbol); } } } }
/** * Bottom-up approach, keeping track of which variables will be read by successor elements. */ private void verifyBlock(CfgBlock block, LiveVariables blockLiveVariables, Set<Symbol> readSymbols) { Set<Symbol> willBeRead = new HashSet<>(blockLiveVariables.getOut()); for (Tree element : Lists.reverse(block.elements())) { Map<Symbol, VariableUsage> usagesInElement = blockLiveVariables.getVariableUsages(element); for (Map.Entry<Symbol, VariableUsage> symbolWithUsage : usagesInElement.entrySet()) { Symbol symbol = symbolWithUsage.getKey(); if (!readSymbols.contains(symbol)) { // will be reported by S1481 continue; } VariableUsage usage = symbolWithUsage.getValue(); if (usage.isWrite() && !usage.isRead()) { if (!willBeRead.contains(symbol) && !shouldSkip(element, symbol)) { context().newIssue(this, element, String.format(MESSAGE_TEMPLATE, symbol.name())); } willBeRead.remove(symbol); } else if (usage.isRead()) { willBeRead.add(symbol); } } } }